This patch supercedes the patch I sent earlier this week to add dependencies to the linker command line. The implementation is different.
First, based on Dave's comment that he wants to keep the interface simple, to enable the linker optimizations no new interface is added. Instead optimizations are enabled in the linker whenever the compiler optimizes, too. I don't think this will create problems at all since the time it takes nowadays is really low; it's only really measurable for extremely large files. The way to add dependencies is changed. Instead of allowing an unstructured string parameter to be added to the command line the new proposed interface allows to introduce a dependency with possibly information about the path the dependency is found. This should be useful and implementable if at some point the explicit linker invocation is replaced by a library implementation. The path argument of the new interface is used differently depending on the name. If the name is of the form -l* then the -L option is used and a runpath is added. Otherwise the path is used to locate the file. Comments? gcc/ChangeLog: 2014-12-06 Ulrich Drepper <drep...@gmail.com> * jit/jit-recording.c (recording::context::add_dependency): New function. (recording::context::~context): Free newly added lists. * jit/jit-recording.h (recording::context): Add new member functions. * jit/libgccjit++.h (context): Add add_dependency member function. * jit/libgccjit.h: Declare gcc_jit_context_add_dependency. * jit/libgccjit.c: Define gcc_jit_context_add_dependency. * jit/libgccjit.map: Add gcc_jit_context_add_dependency. * jit/jit-playback.c (convert_to_dso): Add dependencies and library path arguments to the command line. * docs/topics/contexts.rst: Document new interface. diff -u b/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c --- b/gcc/jit/jit-playback.c +++ b/gcc/jit/jit-playback.c @@ -1749,6 +1749,18 @@ time. */ ADD_ARG ("-fno-use-linker-plugin"); + /* Linker optimization. We always tell the linker to optimize if the + compiler is optimizing, too. */ + if (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL) > 0) + ADD_ARG ("-Wl,-O"); + + const char *s; + for (unsigned i = 0; (s = get_dependency (i)); ++i) + ADD_ARG (s); + + for (unsigned i = 0; (s = get_library_path (i)); ++i) + ADD_ARG (s); + /* pex argv arrays are NULL-terminated. */ ADD_ARG (NULL); diff -u b/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c --- b/gcc/jit/jit-recording.c +++ b/gcc/jit/jit-recording.c @@ -218,6 +218,17 @@ for (i = 0; i < GCC_JIT_NUM_STR_OPTIONS; ++i) free (m_str_options[i]); + char *s; + FOR_EACH_VEC_ELT (m_dependencies, i, s) + { + free (s); + } + + FOR_EACH_VEC_ELT (m_library_path, i, s) + { + free (s); + } + if (m_builtins_manager) delete m_builtins_manager; @@ -871,7 +882,66 @@ m_bool_options[opt] = value ? true : false; } -/* This mutex guards gcc::jit::recording::context::compile, so that only +/* Add the given library to the set of dependencies, or add an error + if it's not recognized. + + Implements the post-error-checking part of + gcc_jit_context_add_dependency. */ +void +recording::context::add_dependency (const char *name, int flags, + const char *path) +{ + if (name == NULL) + { + add_error (NULL, "NULL library name"); + return; + } + /* So far no flags are defined. */ + if (flags != 0) + { + add_error (NULL, + "unrecognized flags value: %i", flags); + return; + } + + bool named_library = strncmp (name, "-l", 2); + + if (strchr (name, '/') != NULL && (named_library || path != NULL)) + { + add_error (NULL, + "path must be NULL unless simple file name is used"); + return; + } + if (named_library == 0 || path == NULL) + { + m_dependencies.safe_push (xstrdup (name)); + + if (named_library) + { + char *v; + asprintf (&v, "-Wl,-R,%s -L %s", path, path); + if (v == NULL) + { + add_error (NULL, "cannot allocate memory"); + return; + } + m_library_path.safe_push (v); + } + } + else + { + char *v; + asprintf (&v, "%s/%s", path, name); + if (v == NULL) + { + add_error (NULL, "cannot allocate memory"); + return; + } + m_dependencies.safe_push (v); + } +} + + /* This mutex guards gcc::jit::recording::context::compile, so that only one thread can be accessing the bulk of GCC's state at once. */ static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER; diff -u b/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h --- b/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -191,6 +191,10 @@ set_bool_option (enum gcc_jit_bool_option opt, int value); + void + add_dependency (const char *name, int flags, + const char *path); + const char * get_str_option (enum gcc_jit_str_option opt) const { @@ -209,6 +213,22 @@ return m_bool_options[opt]; } + const char * + get_dependency (unsigned idx) const + { + if (idx >= m_dependencies.length ()) + return NULL; + return m_dependencies[idx]; + } + + const char * + get_library_path (unsigned idx) const + { + if (idx >= m_library_path.length ()) + return NULL; + return m_library_path[idx]; + } + result * compile (); @@ -250,6 +270,9 @@ int m_int_options[GCC_JIT_NUM_INT_OPTIONS]; bool m_bool_options[GCC_JIT_NUM_BOOL_OPTIONS]; + auto_vec<char *> m_dependencies; + auto_vec<char *> m_library_path; + /* Recorded API usage. */ auto_vec<memento *> m_mementos; diff -u b/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h --- b/gcc/jit/libgccjit++.h +++ b/gcc/jit/libgccjit++.h @@ -108,6 +108,9 @@ void set_bool_option (enum gcc_jit_bool_option opt, int value); + void add_dependency (const char *name, int flags = 0, + const char *path = NULL); + location new_location (const std::string &filename, int line, @@ -561,6 +564,12 @@ } +inline void +context::add_dependency (const char *name, int flags, const char *path) +{ + gcc_jit_context_add_dependency (m_inner_ctxt, name, flags, path); +} + inline location context::new_location (const std::string &filename, int line, diff -u b/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h --- b/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -234,6 +234,16 @@ enum gcc_jit_bool_option opt, int value); +/* Add object as dependency. + + The (const char *) values are not needed anymore after the call + returns. */ +extern void +gcc_jit_context_add_dependency (gcc_jit_context *ctxt, + const char *name, + int flags, + const char *path); + /* This actually calls into GCC and runs the build, all in a mutex for now. The result is a wrapper around a .so file. It can only be called once on a given context. */ only in patch2: unchanged: --- a/gcc/jit/docs/topics/contexts.rst +++ b/gcc/jit/docs/topics/contexts.rst @@ -325,3 +325,47 @@ Integer options -O0 through -O3. The default value is 0 (unoptimized). + + .. macro:: GCC_JIT_INT_OPTION_LINK_OPTIMIZATION_LEVEL + + How much to optimize the code at the linking phase. + + Valid values are 0 and 1. + + The default value is 0 (unoptimized). + +Dependencies +------------ + +The JIT-created code might reference functions which are provided by +external libraries or is available in object files. + +.. function:: void gcc_jit_context_add_dependency (gcc_jit_context *ctxt, \ + const char *name, \ + int flags, \ + const char *path) + + Add the named object to the list of dependencies for the context. + + .. name:: name of the file with the object to be added. The string can + have multiple forms: + + - if the string starts with "-l" it names a library which + is looked up using the usual rules a linker would follow, + possibly extended by the :name `path` parameter. The + :name `name` must consist only of valid characters for a + library name. + + - if the string is a general file name it names a file + available in the file system which can be accessible. The + file can be a library or an object file. + + - if the string is a path name it must name the file. In this + case the :name `path` must be :macro:`NULL`. + + .. flags:: this parameter is reserved for future use and for now must + always be zero. + + .. path:: this parameter provides the path of the file named in the + ``name`` parameter. See above for the rules for when this + parameter must be set to :macro:`NULL`. only in patch2: unchanged: --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -175,6 +175,18 @@ public: return m_recording_ctxt->get_bool_option (opt); } + const char * + get_dependency (unsigned idx) const + { + return m_recording_ctxt->get_dependency (idx); + } + + const char * + get_library_path (unsigned idx) const + { + return m_recording_ctxt->get_library_path (idx); + } + builtins_manager *get_builtins_manager () const { return m_recording_ctxt->get_builtins_manager (); @@ -586,4 +598,3 @@ extern playback::context *active_playback_ctxt; } // namespace gcc #endif /* JIT_PLAYBACK_H */ - only in patch2: unchanged: --- a/gcc/jit/libgccjit.c +++ b/gcc/jit/libgccjit.c @@ -2004,6 +2004,24 @@ gcc_jit_context_set_bool_option (gcc_jit_context *ctxt, /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the + gcc::jit::recording::context::add_library_dependency method in + jit-recording.c. */ + +void gcc_jit_context_add_dependency (gcc_jit_context *ctxt, + const char *name, + int flags, + const char *path) +{ + RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context"); + /* flags is checked in the inner function. */ + + ctxt->add_dependency (name, flags, path); +} + + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the gcc::jit::recording::context::compile method in jit-recording.c. */ only in patch2: unchanged: --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -31,6 +31,7 @@ gcc_jit_block_end_with_void_return; gcc_jit_block_get_function; gcc_jit_context_acquire; + gcc_jit_context_add_dependency; gcc_jit_context_compile; gcc_jit_context_dump_to_file; gcc_jit_context_get_builtin_function; @@ -97,4 +98,4 @@ gcc_jit_type_get_volatile; local: *; -}; \ No newline at end of file +};