Compiler conflates LDFLAGS and LIBS
When compiling with ecl, its build system supports passing flags to the compiler-linker in several places. For example, in src/cmp/cmpdefs.lsp
we find things like,
#-dlopen
(defvar *ld-flags* "@LDFLAGS@ -lecl @CORE_LIBS@ @FASL_LIBS@ @LIBS@")
Those flags then get used by default in src/cmp/cmpmain.lsp
:
#-msvc
(defun linker-cc (o-pathname object-files &key
(type :program)
(ld-flags (split-program-options *ld-flags*)))
(declare (ignore type))
(safe-run-program
*ld*
`("-o" ,(brief-namestring o-pathname)
,(concatenate 'string "-L" (fix-for-mingw (ecl-library-directory)))
,@object-files
,@(and *ld-rpath* (list *ld-rpath*))
,@(split-program-options *user-ld-flags*)
,@ld-flags)))
The high-level interface to that stuff is then the builder
function that takes ld-flags
as an argument, and passes it down to the lower-level functions:
(defun builder (target output-name
&key
lisp-files ld-flags
...
(let ((init-tag (init-name-tag init-name :kind target)))
(ecase target
(:program
...
(compiler-cc c-name o-name)
(linker-cc output-name (list* (namestring o-name) ld-flags)))
...
I'll summarize the problem this causes with a question: what are people supposed to pass in as ld-flags
?
There are two different sets of "linker flags" that are used by autotools and that are supported by gcc in different ways, namely LDFLAGS
and LIBS
. Basically, all of your -l<foo>
flags should go in LIBS
, and everything else should go in LDFLAGS
. Even though both get passed to the linker, especially when using gcc, the distinction is not just an organizational aid. This is because the order of the flags and the arguments to gcc is important. Here's an example, attempting to link one object file named example.o
into an executable named example
. Libcrypto here is superfluous and should be removed by --as-needed
:
LDFLAGS="-Wl,--as-needed"
LIBS="-lcrypto"
gcc ${LDFLAGS} ${LIBS} example.o -o example # doesn't link libcrypto!
gcc example.o ${LDFLAGS} ${LIBS} -o example # doesn't honor --as-needed!
gcc ${LDFLAGS} example.o ${LIBS} -o example # works great!
In short, the placement of your -l<foo>
flags differs from that of all the other linker flags. Since ECL is only providing one big variable ld-flags
for all of the linker flags, there's no correct way to pass in options like --as-needed
and -l<foo>
at the same time.
This problem manifests when building maxima on Gentoo because we add -Wl,--as-needed
to LDFLAGS
while compiling, and maxima passes the value of $LDFLAGS
to ECL as ld-flags
. Since ECL is using ld-flags
internally in a more LIBS
-like role, the flags passed by maxima wind up in the wrong place (and there's no way to fix it without breaking things the other way around).