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;