|Anonymous | Login | Signup for a new account||2016-09-27 17:37 CEST|
|Main | My View | View Issues | Change Log | Roadmap|
|View Issue Details|
|ID||Project||Category||View Status||Date Submitted||Last Update|
|0006186||OCaml||OCamlbuild (the tool)||public||2013-09-20 17:39||2015-12-02 16:05|
|Target Version||later||Fixed in Version|
|Summary||0006186: parameterized tags and non-parameterized tags haven't the same behavior when tagging inside rules|
|Description||According to the following test-case, we are not able to tag (with a parameterized tag) inside a rule, but it works outside a rule and with a non-parameterized tag.|
|Steps To Reproduce||myocamlbuild.ml:|
let () =
rule "test..." ~dep:"%.byte" ~prod:"%.js"
(fun env _ ->
let dep = env "%.byte" in
let prod = env "%.js" in
tag_file prod ["opt(2)"; "test"];
let tags = tags_of_pathname prod ++ "js_of_ocaml" in
Cmd (S [A "js_of_ocaml"; T tags; A dep; A "-o"; A prod])
let () =
pflag ["js_of_ocaml"] "opt" (fun n -> S [A "-opt"; A n]);
flag ["js_of_ocaml"; "test"] (A "-pretty")
$ touch test.ml
$ ocamlbuild -verbose 0 test.js
js_of_ocaml -pretty test.byte -o test.js
And if we add this at the end of the myocamlbuild.ml:
let () = tag_file "test.js" ["opt(1)"]
$ ocamlbuild -verbose 0 test.js
js_of_ocaml -pretty -opt 1 test.byte -o test.js
|Attached Files||param_tags.patch [^] (397 bytes) 2013-09-21 18:17 [Show Content]|
Indeed, this surprising/buggy behavior has been present in ocamlbuild since the introduction of parametrized tags.
The "mental model" is that after everything is initialized (including the user plugin), ocamlbuild will "acknowledge" parametrized tags, that is look for all tags of the form "foo(bar)" that have been used somewhere (in a tag_file command, in the _tags file...), and execute the code of the corresponding parametrized tag with input "bar".
In your code, the tag "opt(2)" only appears dynamically when the rule is executed, and this is after this acknowledgment phase has run, so the tag does not take any meaning. In your workaround, you apply the tag at plugin execution time, so this works fine.
I'm not sure what is a good way to fix this.
I were sure to have mentioned the workaround: https://github.com/jpdeplaix/eliom/commit/747e11cd46422dafdb6886974120da9effe0ef99 [^]
So, maybe we can call Param_tags.init inside Flags.of_tags(_list) or others functions that transforms tags into flags.
I've attached a fix. I don't know if it's the right way (maybe too much performances cost), but at least it fixes the issue.
I don't think that would be correct, and I also doubt that your workaround is actually satisfying.
First, the current implementation of Param_tags.init is apparently designed to be called exactly once during ocamlbuild's initialization (that's explicitly mentioned in the comments). I don't understand the subtleties, but I would be weary of breaking this invariant.
More deeply, in OCamlbuild's current design, tags are purely data. They can be attached to a target either before or after being actually given a semantic by a `flag` or `pflag` call. Acknowledgment is supposed to happen after everything else, which means that both the semantics and the use-sites of tags are available, and it is possible to do some simple sanity checking. 4.00.1 only checks that the arity is correct (non-parametrized tags are not used parametrized, and vice versa) but trunk goes further with a "unused tags" warning. If you were to run Param_tags.init during each tag_file call, you would have false warnings due to sanity-checking running on tags that are attached to targets but have not yet be given a semantics.
I think one would need something more dynamic, such as automatically initializing tags at the moment they are used (that is when they appear in an actual command). The -plugin-tags feature already does something like that, and this is why I added Param_tags.partial_init before 4.01.
Something I was considering independently of this issue is to provide a Tags.declare command that would take a string representation of a tag, and return a tag value (which is a string, so that would be the identity, but with the possibility to do some sort of registration). Instead of
flag ["ocaml"; "link"; "debug"] (A "-g");;
one would have something like
let debug = Tag.declare "debug";;
flag [ocaml; link; debug] (A "-g");;
The purported advantages were to avoid typos in flag declarations (getting the tag variable name wrong would result in a static error) and being able to warn when "unknown" tags are used (currently there is no notion of "unknown" tag). I think that could also help here.
|I just improved a little bit the workaround: https://github.com/ocsigen/eliom/commit/c65bf98d88a4e65f1c399c507687cc9c02ba1467 [^]|
|2013-09-20 17:39||jpdeplaix||New Issue|
|2013-09-21 14:03||gasche||Note Added: 0010389|
|2013-09-21 14:03||gasche||Assigned To||=> gasche|
|2013-09-21 14:03||gasche||Status||new => confirmed|
|2013-09-21 18:17||jpdeplaix||File Added: param_tags.patch|
|2013-09-21 18:25||jpdeplaix||Note Added: 0010390|
|2013-09-21 19:32||jpdeplaix||Tag Attached: patch|
|2013-09-21 22:28||gasche||Note Added: 0010392|
|2014-03-18 16:46||jpdeplaix||Note Added: 0011051|
|2014-07-16 18:23||doligez||Target Version||=> 4.02.1+dev|
|2014-09-04 00:25||doligez||Target Version||4.02.1+dev => undecided|
|2014-09-22 21:40||doligez||Target Version||undecided => 4.02.2+dev / +rc1|
|2015-02-25 23:33||doligez||Target Version||4.02.2+dev / +rc1 => 4.02.3+dev|
|2015-07-10 19:04||doligez||Target Version||4.02.3+dev => 4.03.0+dev / +beta1|
|2015-12-02 16:05||gasche||Target Version||4.03.0+dev / +beta1 => later|
|Copyright © 2000 - 2011 MantisBT Group|