ocaml / ocamlbuild

The legacy OCamlbuild build manager
Other
121 stars 81 forks source link

MPR#7406: Failure : Link list cannot be empty #120

Open gasche opened 7 years ago

gasche commented 7 years ago

In MPR#7406, igo_weiqi_baduk reports an issue when building .native executables with names containing a dot.

ocamlbuild 0.9.3 & OCaml 4.04.0+flambda & OPAM 2.0~alpha4

$ ocamlbuild foo.a.native
-> Failure: Link list cannot be empty

Message present only when the filename contains 2 (or more) .

OK with foo.a.byte (or foo.native)

I could reproduce the issue with 0.9.3 (and OCaml 4.03.0, it does not depend on the OCaml version).

gasche commented 7 years ago

So I found what the cause of the issue was: in Ocaml_compiler.native_compile_ocaml_implem, the function Pathname.update_extensions is used to find the .ml and .cmi that are the source of the .cmx that is going to be produced. There are two distinct functions, update_extension and update_extensions (final s), the first replaces the very last extension, while the second replace all extensions (everything after a .). This means that froma.b.ml, ocamlbuild actually produces a.cmx, not a.b.cmx (in the _build/_log file of a reproduction attempt, you will see the build command ocamlopt.opt -c -o a.cmx a.b.ml). Then the rule for a.b.native goes looking for a.b.cmx, fails to find it, and it results in the error above (ocamlbuild tries to create an executable from an empty list of compiled implementations to link).

The problem is that it is unclear to me that replacing update_extensions by update_extension would be a good idea. There are other situations in OCaml usage where, on the contrary, we expect to strip all extensions, for example a.d.cmx or a.p.cmx would be produced from a.ml. The codebase consistently uses _extensions, and I am not sure what breakage could occur if we changed this.

Note that one reason why a.b.native may be unsupported is that a.b.ml is not a valid OCaml module name; producing an executable from a file of this name works, but trying to use the compiled module from another module cannot work as A.B refers to the module A. I would need to understand better the use-case of the author, as it is not clear to me that trying to support files of the form a.b.ml (at the risk of regression for other use-cases) is worth the trouble.

Fourchaux commented 7 years ago

Oops, sorry for reporting on Mantis (but, it's not so easy to follow the OCaml development between github,IRC,the mailing Lists,the blogs,reddit,twitter,.......)

(You can use : JP Rodi in the Changelog. Thank you).

gasche commented 7 years ago

Hi @Fourchaux, no worries.

Could you say more about why you need the OCaml compiler to produce executables of the form foo.a.naitve? Do I correctly understand that you are writing sources of the name foo.a.ml? What is the use-case for this?

Fourchaux commented 7 years ago

In fact, I saw this because I added .1 .2 etc ... to the name of multiple copies of a file. If supporting these names is causing trouble (and even regressions) , forget it. I really don't need files of the form a.b.ml.

dbuenzli commented 7 years ago

I think it would bring in more problem than it would solve. For compilation units accessed by others it is incompatible with modules and the file system. You can rename your binaries afterwards if this is for the main compilation unit of a binary (which doesn't need to be accessed via the module system).

gasche commented 7 years ago

On the other hand, I am troubled by the fact that the rule that is called to produce a.b.cmx silently produces a.cmx and sees nothing wrong with it. I am inspecting other uses of update_extensions in ocaml_compiler.ml, and I don't think that they can have this effect. I wonder if I should add a warning in this rule when this happens, or at the level of the solver (add a sanity check that the target of the rule is actually produced after the rule finishes succesfully), and/or change this rule to work as it actually should -- that is always produce %.cmx instead of (strip_extensions %).cmx.

fpottier commented 7 years ago

Hello Gabriel, I came across the same error message, Failure: Link list cannot be empty., in an even simpler situation. ocamlbuild is at 0.9.3 and ocaml is at 4.03.0.

The file test.ml contains the following code:

let x = 0

The command line is:

ocamlbuild -cflags "-i" test.byte

In this situation, ocamlc invokes the OCaml compiler, which apparently succeeds, yet ocamlbuild displays this error message and fails with exit code 2.

gasche commented 7 years ago

That there is an error is not surprising: ocamlbuild is trying to build test.byte, but the option you give prevents the production of a compiled object (-i is not like -S that outputs an assembly file and compiles, its use will stop the compilation right after typing). We could try to make the error more palatable to the user; this is a case, similar to one discussed here recently, where the rule ends but has not produced the expected output, we could detect it and abort there.

I think what you are trying to do is ocamlbuild test.inferred.mli test.byte.

fpottier commented 7 years ago

Thanks Gabriel. Sorry, I did not remember that "-i" suppresses the production of an object file. Indeed, it might be good if ocamlbuild explained more clearly that the command failed to produce the expected file.