On Tue, 2018-06-19 at 15:22 +0000, Joseph Myers wrote:
> 
> 
> What should plain
> 
>   gcc -Wl,-rpath=/foo
> 
> do?  Whatever it should do regarding trying to link or not trying to link,
> it should do the same if you also name a header on the command line to be
> compiled to a precompiled header.  So if you don't want it to try to link
> when building a precompiled header, you presumably want it to say "gcc:
> fatal error: no input files" just like if you pass some compilation option
> to GCC, rather than trying to run the linker.

Actually my preference would be for gcc to not call the linker and to
not print an error message.  If I use gcc to call the linker and link
object files into an executable and I pass it compiler options like
'-fauto-inc-dec' or '-Wa,--gdwarf-2' GCC does not complain that it is
not calling the compiler or the assembler.  We seem to accept the fact
that some flags may not be used due to what type of compilation is
being done and just ignore them.  I would like to do the same with
linker flags.

> So the basic question is: is it valid to link a program (or shared
> library) using *only* -Wl, / -Xlinker to provide input files?  Given that
> those are documented as being for passing options rather than input files
> I think it's reasonable to say it's not valid - so when -Wl, / -Xlinker
> are used, their arguments, stored alongside actual linker input files (any
> non-option that doesn't have a file extension known to be a language
> compiled by GCC), should be marked in some way to indicate that they are
> options not input files and so should not by themselves cause linking to
> be done.

I think this seems right.

> Then there's the question of whether -l counts as an input file
> or an option for this purpose.  Using it as an input file is a bit less
> contrived than using -Wl, options for that purpose - for example, it's
> valid to define main in a shared library (there's a glibc test for this),
> and then you can link a program using just -l without naming any
> object files to link - so I'd be inclined to keep it as an input file, not
> an option.

I can see both sides of this and don't feel strongly one way or the
other.  I have attached a new patch that does allow for the use of just
-l options to force the linker to be called.

Currently explicit_link_files gets set for arguments and options that
get sent to the linker and if there are at least one of these then GCC
calls the linker.  I added a new field that gets set for arguments but
not for files and changed GCC to only call the linker if it sees at
least one non-argument input.  Originally I was just not setting
explicit_link_files for arguments but that did not work because
outfiles was still getting set and that was still triggering the linker
call. '-l' arguments are handled in two ways, if the user passes in a
'-l' we count that as an input file (since a user could put main in a
library and pass that to the linker with a -l), but if the -l comes
from a SPEC file (like the -lstdc++ that gets added automtically) we do
not count that as an input to the linker.

I changed explicit_link_files from an array of char to an array of bool
since that was how it was being used and made explicit_link_args to
be an array of bool also.

My reason for wanting this patch is that I build a complete toolchain
with gcc, binutils, and glibc in a non-standard place and then run
the GCC testsuite with:

        make check RUNTESTFLAGS="--tool_opts  '--sysroot=$T/install
-Wl,--dynamic-linker=$T/install/lib/ld-linux-aarch64.so.1 -Wl,-
rpath=$T/install/lib64'"

and without my patch a number of pch tests fail.

Steve Ellcey
sell...@cavium.com


2018-06-22  Steve Ellcey  <sell...@cavium.com>

        * gcc.h (driver): Add explicit_link_args field.
        * gcc.c (driver::driver): Initialize explicit_link_args.
        (driver::~driver): Delete explicit_link_args.
        (driver::prepare_infiles): Allocate explicit_link_args
        and set it if a non library argument is seen.
        (driver::do_spec_on_infiles): Set explicit_link_args
        if linker argument is seen.
        (driver::maybe_run_linker): Do not increment num_linker_inputs
        for linker arguments (only for linker inputs).

diff --git a/gcc/gcc.c b/gcc/gcc.c
index 405d2e3..8c09687 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -7270,6 +7270,7 @@ compare_files (char *cmpfile[])
 
 driver::driver (bool can_finalize, bool debug) :
   explicit_link_files (NULL),
+  explicit_link_args (NULL),
   decoded_options (NULL),
   m_option_suggestions (NULL)
 {
@@ -7279,6 +7280,7 @@ driver::driver (bool can_finalize, bool debug) :
 driver::~driver ()
 {
   XDELETEVEC (explicit_link_files);
+  XDELETEVEC (explicit_link_args);
   XDELETEVEC (decoded_options);
   if (m_option_suggestions)
     {
@@ -8092,7 +8094,8 @@ driver::prepare_infiles ()
 
   /* Record which files were specified explicitly as link input.  */
 
-  explicit_link_files = XCNEWVEC (char, n_infiles);
+  explicit_link_files = XCNEWVEC (bool, n_infiles);
+  explicit_link_args = XCNEWVEC (bool, n_infiles);
 
   combine_inputs = have_o || flag_wpa;
 
@@ -8118,9 +8121,15 @@ driver::prepare_infiles ()
       else
 	{
 	  /* Since there is no compiler for this input file, assume it is a
-	     linker file.  */
-	  explicit_link_files[i] = 1;
+	     linker file or linker argument.  */
+	  explicit_link_files[i] = true;
 	  infiles[i].incompiler = NULL;
+	  /* If this is an argument and not an object to be linked, set
+	     explicit_link_args.  We do not do this for -l because a user
+	     can put objects (including main) into a library linnked with
+	     -l.  */
+	  if (infiles[i].name[0] == '-' && infiles[i].name[1] != 'l')
+	    explicit_link_args[i] = true;
 	}
       infiles[i].compiled = false;
       infiles[i].preprocessed = false;
@@ -8240,7 +8249,15 @@ driver::do_spec_on_infiles () const
 	 record it as explicit linker input.  */
 
       else
-	explicit_link_files[i] = 1;
+	{
+	  explicit_link_files[i] = true;
+	  /* Set explicit_link_args if this is a linker argument and
+	     not a object to be linked.  This includes -l since this
+	     comes from a SPEC file and not from the user.  */
+	  if (infiles[i].name[0] == '-')
+	    explicit_link_args[i] = true;
+
+	}
 
       /* Clear the delete-on-failure queue, deleting the files in it
 	 if this compilation failed.  */
@@ -8293,7 +8310,8 @@ driver::maybe_run_linker (const char *argv0) const
   /* Determine if there are any linker input files.  */
   num_linker_inputs = 0;
   for (i = 0; (int) i < n_infiles; i++)
-    if (explicit_link_files[i] || outfiles[i] != NULL)
+    if ((explicit_link_files[i] || outfiles[i] != NULL)
+	&& !explicit_link_args[i])
       num_linker_inputs++;
 
   /* Run ld to link all the compiler output files.  */
diff --git a/gcc/gcc.h b/gcc/gcc.h
index ddbf42f..79fe7ac 100644
--- a/gcc/gcc.h
+++ b/gcc/gcc.h
@@ -56,7 +56,8 @@ class driver
   int get_exit_code () const;
 
  private:
-  char *explicit_link_files;
+  bool *explicit_link_files;
+  bool *explicit_link_args;
   struct cl_decoded_option *decoded_options;
   unsigned int decoded_options_count;
   auto_vec <char *> *m_option_suggestions;

Reply via email to