Commit 1dda74e0 authored by Marius Gerbershagen's avatar Marius Gerbershagen
Browse files

cmp: introduce new variables for linker flags

Split up the options into additional flags for the linker and
additional libraries.

Quoting from issue #636:

> 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.

Fixes #636.
parent 43be4f6d
......@@ -30,6 +30,11 @@
* Pending changes since 21.2.1
** Enhancements
- Add hook functions for cl:ed via ext:*ed-functions* list
** API changes
- Linker flags like ~-lfoo~ specifiying additional library to link in
should now be added to ~c:*user-ld-libs*~. Previously, these were
contained in ~c:*user-ld-flags*~, which could lead to option flags such
as ~-Wl,foo~ to be added in a wrong place in the C compiler command line.
* 21.2.1 changes since 20.4.24
** Announcement
Dear Community,
......
......@@ -52,17 +52,16 @@ coprocessor).")
(t
"~A -I. \"-I~A\" ~A ~:[~*~;~A~] -w -c \"~A\" -o \"~A\"~{ '~A'~}")))
(defvar *ld-flags* "@LDFLAGS@")
#-dlopen
(defvar *ld-flags* "@LDFLAGS@ -lecl @CORE_LIBS@ @FASL_LIBS@ @LIBS@")
(defvar *ld-libs* "-lecl @CORE_LIBS@ @FASL_LIBS@ @LIBS@")
#+dlopen
(defvar *ld-flags* #-msvc "@LDFLAGS@ -lecl @FASL_LIBS@ @LIBS@"
#+msvc "@LDFLAGS@ ecl.lib @CLIBS@")
(defvar *ld-libs* #-msvc "-lecl @FASL_LIBS@ @LIBS@"
#+msvc "ecl.lib @CLIBS@")
#+dlopen
(defvar *ld-shared-flags* #-msvc "@SHARED_LDFLAGS@ @LDFLAGS@ -lecl @FASL_LIBS@ @LIBS@"
#+msvc "@SHARED_LDFLAGS@ @LDFLAGS@ ecl.lib @CLIBS@")
(defvar *ld-shared-flags* "@SHARED_LDFLAGS@ @LDFLAGS@")
#+dlopen
(defvar *ld-bundle-flags* #-msvc "@BUNDLE_LDFLAGS@ @LDFLAGS@ -lecl @FASL_LIBS@ @LIBS@"
#+msvc "@BUNDLE_LDFLAGS@ @LDFLAGS@ ecl.lib @CLIBS@")
(defvar *ld-bundle-flags* "@BUNDLE_LDFLAGS@ @LDFLAGS@")
(defvar +shared-library-prefix+ "@SHAREDPREFIX@")
(defvar +shared-library-extension+ "@SHAREDEXT@")
......
......@@ -205,9 +205,16 @@ value of *CMP-ENV*.")
(defvar *files-to-be-deleted* '())
(defvar *user-ld-flags* '()
"Flags and options to be passed to the linker when building FASL, shared libraries
and standalone programs. It is not required to surround values with quotes or use
slashes before special characters.")
"Command line flags for additional options (e.g. \"-Wl,foo\" flags) to
be passed to the linker when building FASL, shared libraries and
standalone programs. It is not required to surround values with quotes
or use slashes before special characters.")
(defvar *user-ld-libs* '()
"Command line flags for additional libraries (e.g. \"-lfoo\" flags) to
be passed to the linker when building FASL, shared libraries and
standalone programs. It is not required to surround values with quotes
or use slashes before special characters.")
(defvar *user-cc-flags* '()
"Flags and options to be passed to the C compiler when building FASL, shared libraries
......
......@@ -125,17 +125,40 @@ the environment variable TMPDIR to a different value." template))
(let ((x (string-right-trim '(#\\ #\/) directory-namestring)))
(if (zerop (length x)) "/" x)))
(defun warn-on-library-flag (ld-flags message)
(flet ((is-library-flag (flag)
(or (string= flag "-l" :end1 2) ; match -lfoo
(and ; match foo.so or foo.so.bar but not -foo.so or -foo.so.bar
(>= (length flag) (1+ (length +shared-library-extension+)))
(not (char= (char flag 0) #\-))
(when-let* ((pos-start (search +shared-library-extension+ flag))
(pos-end (+ pos-start (length +shared-library-extension+))))
(and (>= pos-start 1)
(char= (char flag (1- pos-start)) #\.)
(or (= (length flag) pos-end)
(char= (char flag pos-end) #\.))))))))
(when-let ((flags (remove-if-not #'is-library-flag ld-flags)))
(cmpwarn message flags))))
(defun get-user-ld-flags ()
(let ((flags (split-program-options *user-ld-flags*)))
(warn-on-library-flag flags "The flags~{ ~A~} in C:*USER-LD-FLAGS* probably belong into C:*USER-LD-LIBS*")
flags))
#+msvc
(defun linker-cc (o-pathname object-files &key
(type :program)
(ld-flags (split-program-options *ld-flags*)))
(ld-flags (split-program-options *ld-flags*))
(ld-libs (split-program-options *ld-libs*)))
(safe-run-program
*ld*
`(,(concatenate 'string "-Fe" (brief-namestring o-pathname))
,@object-files
,@(split-program-options *ld-rpath*)
,@(split-program-options *user-ld-flags*)
,@(get-user-ld-flags)
,@ld-flags
,@(split-program-options *user-ld-libs*)
,@ld-libs
,(if (eq type :program)
(concatenate 'string "/IMPLIB:prog" (file-namestring o-pathname) ".lib")
"")
......@@ -147,28 +170,31 @@ the environment variable TMPDIR to a different value." template))
#-msvc
(defun linker-cc (o-pathname object-files &key
(type :program)
(ld-flags (split-program-options *ld-flags*)))
(ld-flags (split-program-options *ld-flags*))
(ld-libs (split-program-options *ld-libs*)))
(declare (ignore type))
(safe-run-program
*ld*
`("-o" ,(brief-namestring o-pathname)
,(concatenate 'string "-L" (fix-for-mingw (ecl-library-directory)))
,@(get-user-ld-flags)
,@ld-flags
,@object-files
,@(and *ld-rpath* (list *ld-rpath*))
,@(split-program-options *user-ld-flags*)
,@ld-flags)))
,@(split-program-options *user-ld-libs*)
,@ld-libs)))
(defun linker-ar (output-name o-name ld-flags)
(defun linker-ar (output-name o-name ld-libs)
#-msvc
(static-lib-ar (namestring output-name)
(list* (brief-namestring o-name) ld-flags))
(list* (brief-namestring o-name) ld-libs))
#+msvc
(unwind-protect
(progn
(with-open-file (f "static_lib.tmp" :direction :output
:if-does-not-exist :create :if-exists :supersede)
(format f "/OUT:~A ~A ~{~&\"~A\"~}"
output-name o-name ld-flags))
output-name o-name ld-libs))
(safe-run-program "link" '("-lib" "-nologo" "@static_lib.tmp")))
(when (probe-file "static_lib.tmp")
(cmp-delete-file "static_lib.tmp"))))
......@@ -182,7 +208,8 @@ the environment variable TMPDIR to a different value." template))
#+dlopen
(defun shared-cc (o-pathname object-files)
(let ((ld-flags (split-program-options *ld-shared-flags*)))
(let ((ld-flags (split-program-options *ld-shared-flags*))
(ld-libs (split-program-options *ld-libs*)))
#+msvc
(setf ld-flags
(let ((implib (si::coerce-to-filename
......@@ -196,11 +223,13 @@ the environment variable TMPDIR to a different value." template))
(concatenate 'string "/IMPLIB:" implib)))))
#+mingw32
(setf ld-flags (list* "-shared" ld-flags))
(linker-cc o-pathname object-files :type :dll :ld-flags ld-flags)))
(linker-cc o-pathname object-files :type :dll
:ld-flags ld-flags :ld-libs ld-libs)))
#+dlopen
(defun bundle-cc (o-pathname init-name object-files)
(let ((ld-flags (split-program-options *ld-bundle-flags*)))
(let ((ld-flags (split-program-options *ld-bundle-flags*))
(ld-libs (split-program-options *ld-libs*)))
#+msvc
(setf ld-flags
(let ((implib (si::coerce-to-filename
......@@ -217,7 +246,8 @@ the environment variable TMPDIR to a different value." template))
(concatenate 'string "/IMPLIB:" implib)))))
#+mingw32
(setf ld-flags (list* "-shared" "-Wl,--export-all-symbols" ld-flags))
(linker-cc o-pathname object-files :type :fasl :ld-flags ld-flags)))
(linker-cc o-pathname object-files :type :fasl
:ld-flags ld-flags :ld-libs ld-libs)))
(defconstant +lisp-program-header+ "
#include <ecl/ecl.h>
......@@ -417,7 +447,7 @@ filesystem or in the database of ASDF modules."
(defun builder (target output-name
&key
lisp-files ld-flags
lisp-files ld-flags ld-libs
(init-name nil)
(main-name nil)
(prologue-code "")
......@@ -432,6 +462,9 @@ filesystem or in the database of ASDF modules."
output-name))
;; wrap-name is the init function name defined by a programmer
(wrap-name init-name))
(warn-on-library-flag ld-flags "The flags~{ ~A~} in the :LD-FLAGS argument to C::BUILDER probably belong into the :LD-LIBS argument")
;; init-name should always be unique
(setf init-name (compute-init-name output-name :kind target))
(cond ((null wrap-name) nil)
......@@ -517,7 +550,7 @@ output = si_safe_eval(2, ecl_read_from_cstring(lisp_code), ECL_NIL);
(let* ((init-fn (guess-init-name path kind))
(flags (guess-ld-flags path)))
;; We should give a warning that we cannot link this module in
(when flags (push flags ld-flags))
(when flags (push flags ld-libs))
(when init-fn
(push (list init-fn path) submodules)))))
(setq c-file (open c-name :direction :output :external-format :default))
......@@ -537,7 +570,8 @@ output = si_safe_eval(2, ecl_read_from_cstring(lisp_code), ECL_NIL);
prologue-code init-name epilogue-code)
(close c-file)
(compiler-cc c-name o-name)
(linker-cc output-name (list* (namestring o-name) ld-flags)))
(linker-cc output-name (append ld-flags (list (namestring o-name))
ld-libs)))
(:static-library
(format c-file +lisp-program-init+
init-name init-tag prologue-code submodules epilogue-code)
......@@ -548,7 +582,7 @@ output = si_safe_eval(2, ecl_read_from_cstring(lisp_code), ECL_NIL);
(close c-file)
(compiler-cc c-name o-name)
(when (probe-file output-name) (delete-file output-name))
(linker-ar output-name o-name ld-flags))
(linker-ar output-name o-name ld-libs))
#+dlopen
(:shared-library
(format c-file +lisp-program-init+
......@@ -559,7 +593,8 @@ output = si_safe_eval(2, ecl_read_from_cstring(lisp_code), ECL_NIL);
main-name prologue-code init-name epilogue-code)
(close c-file)
(compiler-cc c-name o-name)
(shared-cc output-name (list* o-name ld-flags)))
(shared-cc output-name (append ld-flags (list o-name)
ld-libs)))
#+dlopen
(:fasl
(format c-file +lisp-program-init+ init-name init-tag prologue-code
......@@ -568,7 +603,8 @@ output = si_safe_eval(2, ecl_read_from_cstring(lisp_code), ECL_NIL);
;(format c-file +lisp-init-wrapper+ wrap-name init-name)
(close c-file)
(compiler-cc c-name o-name)
(bundle-cc output-name init-name (list* o-name ld-flags))))
(bundle-cc output-name init-name (append ld-flags (list o-name)
ld-libs))))
(mapc 'cmp-delete-file tmp-names)
(cmp-delete-file c-name)
(cmp-delete-file o-name)
......
......@@ -86,24 +86,24 @@
#+msvc "@CFLAGS@ @ECL_CFLAGS@"
c::*ecl-include-directory* "@true_builddir@/"
c::*ecl-library-directory* "@true_builddir@/")
#-:wants-dlopen
(setf c::*ld-flags*
"@LDFLAGS@ @LIBPREFIX@ecl.@LIBEXT@ @CORE_LIBS@ @FASL_LIBS@ @LIBS@")
(setf c::*ld-flags* "@LDFLAGS@")
#-:wants-dlopen
(setf c::*ld-libs* "@LIBPREFIX@ecl.@LIBEXT@ @CORE_LIBS@ @FASL_LIBS@ @LIBS@")
#+(and :wants-dlopen (not nonstop))
(setf c::*ld-flags*
"@LDFLAGS@ @SHAREDPREFIX@ecl.@SHAREDEXT@ @LIBS@"
(setf c::*ld-libs*
"@SHAREDPREFIX@ecl.@SHAREDEXT@ @LIBS@"
c::*ld-shared-flags*
"@SHARED_LDFLAGS@ @LDFLAGS@ @SHAREDPREFIX@ecl.@SHAREDEXT@ @FASL_LIBS@ @LIBS@"
"@SHARED_LDFLAGS@ @LDFLAGS@"
c::*ld-bundle-flags*
"@BUNDLE_LDFLAGS@ @LDFLAGS@ @SHAREDPREFIX@ecl.@SHAREDEXT@ @FASL_LIBS@ @LIBS@")
"@BUNDLE_LDFLAGS@ @LDFLAGS@")
;;; FIXME: The nonstop platform does not support soname
#+(and :wants-dlopen nonstop)
(setf c::*ld-flags*
"@LDFLAGS@ -Wld=-l@SHAREDPREFIX@ecl.@SHAREDEXT@ @LIBS@"
(setf c::*ld-libs*
"-Wld=-l@SHAREDPREFIX@ecl.@SHAREDEXT@ @LIBS@"
c::*ld-shared-flags*
"@SHARED_LDFLAGS@ @LDFLAGS@ -Wld=-l@SHAREDPREFIX@ecl.@SHAREDEXT@ @FASL_LIBS@ @LIBS@"
"@SHARED_LDFLAGS@ @LDFLAGS@ -Wld=-l@SHAREDPREFIX@ecl.@SHAREDEXT@"
c::*ld-bundle-flags*
"@BUNDLE_LDFLAGS@ @LDFLAGS@ -Wld=-l@SHAREDPREFIX@ecl.@SHAREDEXT@ @FASL_LIBS@ @LIBS@")
"@BUNDLE_LDFLAGS@ @LDFLAGS@ -Wld=-l@SHAREDPREFIX@ecl.@SHAREDEXT@")
;;;
;;; * Avoid name clashes with user supplied code.
......@@ -162,8 +162,10 @@
;;;
;;; We do not need the -rpath flag for the library, nor -lecl.
;;;
(let* ((c::*ld-shared-flags* #-msvc "@SHARED_LDFLAGS@ @LDFLAGS@ @SONAME_LDFLAGS@ @CORE_LIBS@ @FASL_LIBS@ @LIBS@"
#+msvc "@SHARED_LDFLAGS@ @LDFLAGS@ @STATICLIBS@ @CLIBS@")
(let* ((c::*ld-shared-flags* #-msvc "@SHARED_LDFLAGS@ @LDFLAGS@ @SONAME_LDFLAGS@"
#+msvc "@SHARED_LDFLAGS@ @LDFLAGS@")
(c::*ld-libs* #-msvc "@CORE_LIBS@ @FASL_LIBS@ @LIBS@"
#+msvc "@STATICLIBS@ @CLIBS@")
(c::*cc-flags* (concatenate 'string "-DECL_API -I@true_builddir@/c " c::*cc-flags*))
(extra-args nil))
#+(or mingw32 cygwin)
......
......@@ -544,8 +544,15 @@ shared libraries and standalone programs.
@end deftypevar
@deftypevar string {c:*user-ld-flags*}
Flags and options to be passed to the linker when building FASL,
shared libraries and standalone programs.
Flags for options (e.g. @code{-Wl,foo} flags, usually in the
@code{$LDFLAGS} variable in autoconf) to be passed to the linker when
building FASL, shared libraries and standalone programs.
@end deftypevar
@deftypevar string {c:*user-ld-libs*}
Flags for libraries (e.g. @code{-lfoo} flags, usually in the
@code{$LIBS} variable in autoconf) to be passed to the linker when
building FASL, shared libraries and standalone programs.
@end deftypevar
@deftypevar string {c:*cc-optimize*}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment