2828#include < set>
2929#include < string_view>
3030#include < numeric>
31+ #include < cassert>
3132
3233#include < spdlog/spdlog.h>
3334
3435using namespace cs ::semantic;
3536
3637namespace {
3738
39+ enum class LibraryPriorityType {
40+ FIRSTLY_SHARED,
41+ ONLY_STATIC,
42+ ONLY_STATIC_FIXED
43+ };
44+
3845 // https://gcc.gnu.org/onlinedocs/cpp/Environment-Variables.html
3946 Arguments flags_from_environment (const std::map<std::string, std::string> &environment) {
4047 Arguments flags;
@@ -71,6 +78,19 @@ namespace {
7178 return input_arguments;
7279 }
7380
81+ std::vector<std::string> get_library_directories (const Execution &execution) {
82+ std::vector<std::string> library_directories;
83+ if (const auto it = execution.environment .find (" LIBRARY_PATH" ); it != execution.environment .end ())
84+ {
85+ for (const auto &path : sys::path::split (it->second )) {
86+ auto directory = (path.empty ()) ? " ." : path.string ();
87+ library_directories.emplace_back (directory);
88+ }
89+ }
90+
91+ return library_directories;
92+ }
93+
7494 bool is_compiler_query (const CompilerFlags& flags)
7595 {
7696 // no flag is a no compilation
@@ -104,17 +124,117 @@ namespace {
104124 });
105125 }
106126
127+ std::string directory_path_from_flag (const CompilerFlag& flag) {
128+ assert (flag.type == CompilerFlagType::DIRECTORY_SEARCH_LIBRARY);
129+
130+ if (flag.arguments .front () == " -L" ) {
131+ return flag.arguments .back ();
132+ }
133+ return flag.arguments .front ().substr (2 );
134+ }
135+
136+ std::string library_name_from_flag (const CompilerFlag& flag) {
137+ assert (flag.type == CompilerFlagType::LINKER_LIBRARY_FLAG);
138+
139+ if (flag.arguments .front () == " -l" ) {
140+ return flag.arguments .back ();
141+ }
142+ return flag.arguments .front ().substr (2 );
143+ }
144+
145+ std::optional<fs::path> find_library (
146+ const std::string& libname,
147+ const std::vector<std::string>& library_directories,
148+ const std::vector<std::string>& added_library_directories,
149+ const LibraryPriorityType type
150+ ) {
151+ static const std::vector<std::string> shared_extensions = {
152+ " .so" , " .dylib" , " .dll" , " .DLL" , " .ocx" , " .OCX" , " .lib" , " .LIB" , " .library"
153+ };
154+ static const std::vector<std::string> static_extensions = {
155+ " .a" , " .lib" , " .LIB"
156+ };
157+
158+ const std::string libname_with_prefix = " lib" + libname;
159+
160+ const auto find_lib = [&libname_with_prefix](
161+ const std::vector<std::string>& dirs,
162+ const std::vector<std::string>& extensions
163+ ) -> std::optional<std::string> {
164+ for (const auto & dir : dirs) {
165+ for (const auto & extension: extensions) {
166+ fs::path libname_full = dir;
167+ libname_full /= libname_with_prefix + extension;
168+
169+ if (fs::exists (libname_full)) {
170+ return std::make_optional (libname_full);
171+ }
172+ }
173+ }
174+ return std::nullopt ;
175+ };
176+
177+ if (type == LibraryPriorityType::FIRSTLY_SHARED) {
178+ if (const auto lib = find_lib (added_library_directories, shared_extensions); lib.has_value ()) {
179+ return lib;
180+ }
181+ if (const auto lib = find_lib (library_directories, shared_extensions); lib.has_value ()) {
182+ return lib;
183+ }
184+ }
185+
186+ if (const auto lib = find_lib (added_library_directories, static_extensions); lib.has_value ()) {
187+ return lib;
188+ }
189+ if (const auto lib = find_lib (library_directories, static_extensions); lib.has_value ()) {
190+ return lib;
191+ }
192+
193+ return std::nullopt ;
194+ }
195+
196+ inline bool contains_static_flag (const CompilerFlags &flags) {
197+ return std::any_of (flags.begin (), flags.end (), [](const auto & flag) {
198+ return flag.type == CompilerFlagType::LINKER_LIBRARY_STATIC;
199+ });
200+ }
201+
202+ void processing_linker_options_flag (const CompilerFlag& flag, LibraryPriorityType& type) {
203+ const auto & options = flag.arguments .front ();
204+ size_t option_start = 0 ;
205+
206+ while (option_start < options.size ()) {
207+ size_t option_end = options.find (' ,' , option_start);
208+ if (option_end == std::string::npos) {
209+ option_end = options.size ();
210+ }
211+ const auto option = options.substr (option_start, option_end - option_start);
212+ if (type != LibraryPriorityType::ONLY_STATIC_FIXED && option == " -Bdynamic" ) {
213+ type = LibraryPriorityType::FIRSTLY_SHARED;
214+ }
215+ if (type != LibraryPriorityType::ONLY_STATIC_FIXED && option == " -Bstatic" ) {
216+ type = LibraryPriorityType::ONLY_STATIC;
217+ }
218+ option_start = option_end + 1 ;
219+ }
220+ }
221+
107222 std::tuple<
108223 Arguments,
109224 std::list<fs::path>,
110225 std::list<fs::path>,
111226 std::optional<fs::path>
112- > split_compile (const CompilerFlags &flags) {
227+ > split_compile (const CompilerFlags &flags, const std::vector<std::string>& library_directories ) {
113228 Arguments arguments;
114229 std::list<fs::path> sources;
115230 std::list<fs::path> dependencies;
116231 std::optional<fs::path> output;
117232
233+ std::vector<std::string> added_library_directories;
234+ LibraryPriorityType type = (contains_static_flag (flags))
235+ ? LibraryPriorityType::ONLY_STATIC_FIXED
236+ : LibraryPriorityType::FIRSTLY_SHARED;
237+
118238 for (const auto &flag : flags) {
119239 switch (flag.type ) {
120240 case CompilerFlagType::KIND_OF_OUTPUT_OUTPUT: {
@@ -133,6 +253,21 @@ namespace {
133253 dependencies.emplace_back (candidate);
134254 break ;
135255 }
256+ case CompilerFlagType::LINKER_OPTIONS_FLAG: {
257+ processing_linker_options_flag (flag, type);
258+ break ;
259+ }
260+ case CompilerFlagType::DIRECTORY_SEARCH_LIBRARY: {
261+ added_library_directories.push_back (directory_path_from_flag (flag));
262+ break ;
263+ }
264+ case CompilerFlagType::LINKER_LIBRARY_FLAG: {
265+ const auto library = find_library (library_name_from_flag (flag), library_directories, added_library_directories, type);
266+ if (library.has_value ()) {
267+ dependencies.push_back (library.value ());
268+ }
269+ break ;
270+ }
136271 default : {
137272 break ;
138273 }
@@ -147,12 +282,17 @@ namespace {
147282 std::list<fs::path>,
148283 std::optional<fs::path>,
149284 size_t
150- > split_link_with_updating_sources (const CompilerFlags &flags) {
285+ > split_link_with_updating_sources (const CompilerFlags &flags, const std::vector<std::string>& library_directories ) {
151286 Arguments arguments;
152287 std::list<fs::path> files;
153288 std::optional<fs::path> output;
154289 size_t sources_count = 0 ;
155290
291+ std::vector<std::string> added_library_directories;
292+ LibraryPriorityType type = (contains_static_flag (flags))
293+ ? LibraryPriorityType::ONLY_STATIC_FIXED
294+ : LibraryPriorityType::FIRSTLY_SHARED;
295+
156296 for (const auto &flag : flags) {
157297 switch (flag.type ) {
158298 case CompilerFlagType::KIND_OF_OUTPUT_OUTPUT: {
@@ -163,20 +303,35 @@ namespace {
163303 case CompilerFlagType::SOURCE: {
164304 sources_count++;
165305 const auto source_after_compilation = flag.arguments .front () + " .o" ;
166- arguments.push_back (source_after_compilation);
167306 files.emplace_back (source_after_compilation);
168- break ;
307+ arguments.push_back (source_after_compilation);
308+ continue ;
169309 }
170310 case CompilerFlagType::LIBRARY:
171311 case CompilerFlagType::OBJECT_FILE: {
172- arguments.push_back (flag.arguments .front ());
173312 files.emplace_back (flag.arguments .front ());
174313 break ;
175314 }
315+ case CompilerFlagType::LINKER_OPTIONS_FLAG: {
316+ processing_linker_options_flag (flag, type);
317+ break ;
318+ }
319+ case CompilerFlagType::DIRECTORY_SEARCH_LIBRARY: {
320+ added_library_directories.push_back (directory_path_from_flag (flag));
321+ break ;
322+ }
323+ case CompilerFlagType::LINKER_LIBRARY_FLAG: {
324+ const auto library = find_library (library_name_from_flag (flag), library_directories, added_library_directories, type);
325+ if (library.has_value ()) {
326+ files.push_back (library.value ());
327+ }
328+ break ;
329+ }
176330 default : {
177- std::copy (flag. arguments . begin (), flag. arguments . end (), std::back_inserter (arguments)) ;
331+ break ;
178332 }
179333 }
334+ std::copy (flag.arguments .begin (), flag.arguments .end (), std::back_inserter (arguments));
180335 }
181336 return std::make_tuple (arguments, files, output, sources_count);
182337 }
@@ -252,12 +407,12 @@ namespace cs::semantic {
252407 {" -iwithprefixbefore" , {MatchInstruction::EXACTLY_WITH_1_OPT_SEP, CompilerFlagType::DIRECTORY_SEARCH}},
253408 {" -isysroot" , {MatchInstruction::EXACTLY_WITH_1_OPT_SEP, CompilerFlagType::DIRECTORY_SEARCH}},
254409 {" -imultilib" , {MatchInstruction::EXACTLY_WITH_1_OPT_SEP, CompilerFlagType::DIRECTORY_SEARCH}},
255- {" -L" , {MatchInstruction::EXACTLY_WITH_1_OPT_GLUED_OR_SEP, CompilerFlagType::DIRECTORY_SEARCH_LINKER }},
410+ {" -L" , {MatchInstruction::EXACTLY_WITH_1_OPT_GLUED_OR_SEP, CompilerFlagType::DIRECTORY_SEARCH_LIBRARY }},
256411 {" -B" , {MatchInstruction::EXACTLY_WITH_1_OPT_GLUED_OR_SEP, CompilerFlagType::DIRECTORY_SEARCH}},
257412 {" --sysroot" , {MatchInstruction::EXACTLY_WITH_1_OPT_GLUED_WITH_EQ, CompilerFlagType::DIRECTORY_SEARCH}},
258413 {" -flinker-output" , {MatchInstruction::EXACTLY_WITH_1_OPT_GLUED_WITH_EQ, CompilerFlagType::LINKER}},
259414 {" -fuse-ld" , {MatchInstruction::EXACTLY_WITH_1_OPT_GLUED_WITH_EQ, CompilerFlagType::LINKER}},
260- {" -l" , {MatchInstruction::EXACTLY_WITH_1_OPT_GLUED_OR_SEP, CompilerFlagType::LINKER }},
415+ {" -l" , {MatchInstruction::EXACTLY_WITH_1_OPT_GLUED_OR_SEP, CompilerFlagType::LINKER_LIBRARY_FLAG }},
261416 {" -nostartfiles" , {MatchInstruction::EXACTLY, CompilerFlagType::LINKER}},
262417 {" -nodefaultlibs" , {MatchInstruction::EXACTLY, CompilerFlagType::LINKER}},
263418 {" -nolibc" , {MatchInstruction::EXACTLY, CompilerFlagType::LINKER}},
@@ -271,11 +426,12 @@ namespace cs::semantic {
271426 {" -rdynamic" , {MatchInstruction::EXACTLY, CompilerFlagType::LINKER}},
272427 {" -s" , {MatchInstruction::EXACTLY, CompilerFlagType::LINKER}},
273428 {" -symbolic" , {MatchInstruction::EXACTLY, CompilerFlagType::LINKER}},
274- {" -static" , {MatchInstruction::PREFIX, CompilerFlagType::LINKER}},
429+ {" -static" , {MatchInstruction::EXACTLY, CompilerFlagType::LINKER_LIBRARY_STATIC}},
430+ {" -static-" , {MatchInstruction::PREFIX, CompilerFlagType::LINKER}},
275431 {" -shared" , {MatchInstruction::PREFIX, CompilerFlagType::LINKER}},
276432 {" -T" , {MatchInstruction::EXACTLY_WITH_1_OPT_SEP, CompilerFlagType::LINKER}},
277433 {" -Xlinker" , {MatchInstruction::EXACTLY_WITH_1_OPT_SEP, CompilerFlagType::LINKER}},
278- {" -Wl," , {MatchInstruction::PREFIX, CompilerFlagType::LINKER }},
434+ {" -Wl," , {MatchInstruction::PREFIX, CompilerFlagType::LINKER_OPTIONS_FLAG }},
279435 {" -u" , {MatchInstruction::EXACTLY_WITH_1_OPT_SEP, CompilerFlagType::LINKER}},
280436 {" -z" , {MatchInstruction::EXACTLY_WITH_1_OPT_SEP, CompilerFlagType::LINKER}},
281437 {" -Xassembler" , {MatchInstruction::EXACTLY_WITH_1_OPT_SEP, CompilerFlagType::OTHER}},
@@ -358,7 +514,7 @@ namespace cs::semantic {
358514 }
359515
360516 // arguments contains everything except output and sources
361- auto [arguments, sources, dependencies, output] = split_compile (flags);
517+ auto [arguments, sources, dependencies, output] = split_compile (flags, get_library_directories (execution) );
362518 if (sources.empty ()) {
363519 return rust::Err (std::runtime_error (" Source files not found for compilation." ));
364520 }
@@ -403,7 +559,7 @@ namespace cs::semantic {
403559 }
404560
405561 // arguments contains everything except output
406- auto [arguments, files, output, sources_count] = split_link_with_updating_sources (flags);
562+ auto [arguments, files, output, sources_count] = split_link_with_updating_sources (flags, get_library_directories (execution) );
407563 if (sources_count != 0 && !has_linker (flags)) {
408564 return rust::Err (std::runtime_error (" Without linking." ));
409565 }
0 commit comments