Skip to content

Commit 4cbc9a0

Browse files
committed
Add processing of linking flags -l -Wl -L (#8)
* Add processing of linking flags -l -Wl -L * Separate -static flag from -static-s * Supplement testing system, add processing libs for compilation database
1 parent ccd7215 commit 4cbc9a0

File tree

12 files changed

+452
-165
lines changed

12 files changed

+452
-165
lines changed

source/citnames/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ if (ENABLE_UNIT_TESTS)
6666
test/OutputTest.cc
6767
test/ParserTest.cc
6868
test/ToolClangTest.cc
69-
test/ToolGccTest.cc
69+
test/ToolGccCompileTest.cc
70+
test/ToolGccLinkTest.cc
7071
test/ToolWrapperTest.cc
7172
test/ToolArTest.cc
7273
)

source/citnames/source/semantic/Parsers.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@ namespace cs::semantic {
106106
PREPROCESSOR_MAKE,
107107
LINKER,
108108
DIRECTORY_SEARCH,
109-
DIRECTORY_SEARCH_LINKER,
110109
OTHER,
111110
STATIC_ANALYZER,
112111
UNKNOWN,
@@ -116,6 +115,11 @@ namespace cs::semantic {
116115
LIBRARY,
117116

118117
KIND_OF_OUTPUT_OUTPUT,
118+
119+
DIRECTORY_SEARCH_LIBRARY,
120+
LINKER_LIBRARY_FLAG,
121+
LINKER_LIBRARY_STATIC,
122+
LINKER_OPTIONS_FLAG,
119123
};
120124

121125
struct CompilerFlag {

source/citnames/source/semantic/ToolGcc.cc

Lines changed: 168 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,20 @@
2828
#include <set>
2929
#include <string_view>
3030
#include <numeric>
31+
#include <cassert>
3132

3233
#include <spdlog/spdlog.h>
3334

3435
using namespace cs::semantic;
3536

3637
namespace {
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

Comments
 (0)