Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to split all variables & proper error when using them in strings #309

Closed
wants to merge 5 commits into from

Conversation

Chris00
Copy link
Member

@Chris00 Chris00 commented Nov 5, 2017

Fix issue #300

@dra27
Copy link
Member

dra27 commented Nov 5, 2017

I haven't looked closely, but what happens, for example, if $CC is C:\Program Files\Microsoft Visual Studio\...\cl.exe -WX?

@Chris00
Copy link
Member Author

Chris00 commented Nov 5, 2017

@dra27 Yes, I forgot to mention that I'm not convinced that String.extract_blank_separated_words is the right function to use to split the command. Is there already a splitting function that understand the command as the shell does? BTW, what is the value of bytecomp_c_compiler (in _build/log) on Windows?

@rgrinberg
Copy link
Member

@Chris00 do you have a CLA submitted to JST? You might want to get that done while we're reviewing this PR.

@Chris00
Copy link
Member Author

Chris00 commented Nov 7, 2017 via email

@rgrinberg
Copy link
Member

here

@rgrinberg
Copy link
Member

BTW, what is the value of bytecomp_c_compiler (in _build/log) on Windows?

If you have a windows box ready, then it's just bytecomp_c_compiler from ocamlc -config.

Is there already a splitting function that understand the command as the shell does?

I don't think so

@Chris00
Copy link
Member Author

Chris00 commented Nov 8, 2017

@rgrinberg I do not have a Windows box, that's why I was asking (I could run AppVeyor but I do not have the time to write the script right now).

@dra27
Copy link
Member

dra27 commented Nov 8, 2017

It doesn't include by default include a hard-coded directory. Here's a 4.06 msvc64 example: cl -nologo -O2 -Gy- -MD -D_CRT_SECURE_NO_DEPRECATE.

This should work - I'm just wondering whether we should use this opportunity to do some better for specifying compound "commands" like this. I'm for example having to use hacks to get jbuilder to run the compiler when it's a bytecode image with no header (so has to be invoked via ocamlrun).

It's tempting to allow this now, but if we then improve the handling later we'd probably want to remove this behaviour again?

@Chris00
Copy link
Member Author

Chris00 commented Nov 8, 2017

@dra27 Could you precise what you have in mind? I wonder if variables are considered as lists (${CC} but also ${^}) should not be by default split because that's what the user expects. on can always use, say "${^}", if one wants to space-concatenate the list as a single argument (instead of raising an error as of now, it would automatically convert the list to a string).

@dra27
Copy link
Member

dra27 commented Nov 8, 2017

What concerns me slightly is that the present ${!^} and ${!@} do not split strings up, rather they do not concatenate lists in the first place (i.e. if any of the paths involved in the dependencies contain spaces, they will not generate extra entries).

I'm wondering if jbuilder should be doing something (potentially hideous) along the lines of how CreateProcess works - so ${CC} should just be automatically split when used in the "head" context of a (run.

This isn't entirely hypothetical - I know for example that LexiFi use absolute paths to C compilers in order to differentiate 32 and 64-bit Microsoft C compilers, so while I think what you're suggesting here works now, I can see a problem lurking shortly round the corner...

@dra27
Copy link
Member

dra27 commented Nov 8, 2017

I also have a small fear that we're heading towards ${GNU-make-function CC} if we're not careful!

@Chris00
Copy link
Member Author

Chris00 commented Nov 8, 2017

I'm wondering if jbuilder should be doing something (potentially hideous) along the lines of how CreateProcess works - so ${CC} should just be automatically split when used in the "head" context of a (run.

I think it should be the other way around: ${CC} should be a split variable by default and "${CC}" turns it into a single argument — as it would be with a shell variable.

@dra27
Copy link
Member

dra27 commented Nov 8, 2017

Yes, but what therefore does "split" mean - because just splitting it on spaces is not semantically correct when the first "component" should itself include some spaces.

The shell's not the greatest inspiration for this, as it tends to be a nightmare there too!

@Chris00
Copy link
Member Author

Chris00 commented Nov 8, 2017

The variable CC is (was) constructed by jbuilder as a string. However, the C compiler comes from a separate variable context.c_compiler which is no longer concatenated in my patch. So spaces in the compiler path are handled correctly. The problem is that the context.ocamlc_cflags must be split in order to be interpreted correctly by run — that split must be the same as for a Unix shell (maybe even on Windows since the compilation is done with Cygwin, but you know better).

@dra27 dra27 closed this Nov 15, 2017
@dra27 dra27 reopened this Nov 15, 2017
Copy link
Member

@dra27 dra27 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for taking a while to review this properly. Minor changes - it basically looks good to me. My previous concern about splitting program names with spaces incorrectly was, as you politely pointed out, erroneous as it'll only be as bad as the output of ocamlc -config (i.e. it's good in 4.06.0+ where the compiler and flags are separate items and potentially bad in older versions)

src/action.ml Outdated
@@ -200,7 +200,8 @@ module Var_expansion = struct
| Paths (l, Concat) -> [concat (List.map l ~f:(string_of_path ~dir))]

let to_string ~dir = function
| Strings (_, Split) | Paths (_, Split) -> assert false
| Strings (_, Split) | Paths (_, Split) ->
failwith "Action.Var_expansion.to_string"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that this wants to be matched on later, I think it would be better to define an exception, rather than use Failure

src/action.ml Outdated
try Some (VE.to_string ~dir e)
with Failure _ ->
let msg = sprintf "Split variable %S in string does not \
make sense" var in
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the message, I'd match an explicit exception just to guard against some future additional failure mode.

I know there's another message which refers to things not making sense, but I think something more descriptive of what doesn't make sense would be better, e.g. "${!%S} is a list and so cannot be used in a string (did you mean just ${%S}"

It's also tempting just to say that "${!@}" = "${@}"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's also tempting just to say that "${!@}" = "${@}"

Indeed! (My take on this is that splitable variables should come be default as such — so that, say, (run ${CC} always does what is expected — and are concatenated with spaces if used in a string — e.g. (run "${CC}" to have the old behavior) .

let expand_var_no_root t var = String_map.find var t.vars
let expand_var_no_root t var cos =
match String_map.find var t.vars with
| Some v -> Some(v cos)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: space before the (

let p = List.map p ~f:Path.to_string in
Some (String.concat ~sep:" " p)
| Some(Strings(s,_)) -> Some (String.concat ~sep:" " s)
| None -> None)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please could this be refactored as a function and a call to Option.map?

[ "-verbose" , str_exp [] (*"-verbose";*)
; "CPP" , str_exp (context.c_compiler :: cflags @ ["-E"])
; "PA_CPP" , str_exp (context.c_compiler :: cflags
@ ["-undef -traditional"; "-x"; "c"; "-E"])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't "-undef -traditional" be "-undef"; "-traditional"?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

@Chris00
Copy link
Member Author

Chris00 commented Nov 15, 2017

I'll try to make the requested changes tomorrow.

@dra27
Copy link
Member

dra27 commented Nov 15, 2017

Thank you - I shall endeavour not to take so long to review them this time!

@Chris00
Copy link
Member Author

Chris00 commented Nov 23, 2017

To show what I meant by "splitable variables should come be default as such", see #336

@ghost
Copy link

ghost commented Jan 18, 2018

I suppose that #336 replaced this PR

@ghost ghost closed this Jan 18, 2018
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants