GCC Code Coverage Report


Directory: ../
File: src/linker/ExternalLinkerInterface.cpp
Date: 2025-02-05 01:09:36
Exec Total Coverage
Lines: 32 36 88.9%
Functions: 5 5 100.0%
Branches: 36 82 43.9%

Line Branch Exec Source
1 // Copyright (c) 2021-2025 ChilliBits. All rights reserved.
2
3 #include "ExternalLinkerInterface.h"
4 #include "util/Timer.h"
5
6 #include <iostream>
7
8 #include <exception/CompilerError.h>
9 #include <exception/LinkerError.h>
10 #include <util/FileUtil.h>
11
12 namespace spice::compiler {
13
14 187 void ExternalLinkerInterface::prepare() {
15 // Set target to linker
16
2/4
✓ Branch 0 (2→3) taken 187 times.
✗ Branch 1 (2→50) not taken.
✓ Branch 2 (3→4) taken 187 times.
✗ Branch 3 (3→48) not taken.
187 addLinkerFlag("--target=" + cliOptions.targetTriple);
17
18 // Static linking
19
1/2
✗ Branch 0 (5→6) not taken.
✓ Branch 1 (5→13) taken 187 times.
187 if (cliOptions.staticLinking)
20 addLinkerFlag("-static");
21
22 // Stripping symbols
23
2/2
✓ Branch 0 (13→14) taken 185 times.
✓ Branch 1 (13→21) taken 2 times.
187 if (!cliOptions.generateDebugInfo)
24
2/4
✓ Branch 0 (16→17) taken 185 times.
✗ Branch 1 (16→59) not taken.
✓ Branch 2 (17→18) taken 185 times.
✗ Branch 3 (17→57) not taken.
370 addLinkerFlag("-Wl,-s");
25
26 // Web Assembly
27
3/6
✓ Branch 0 (22→23) taken 187 times.
✗ Branch 1 (22→25) not taken.
✗ Branch 2 (24→25) not taken.
✓ Branch 3 (24→26) taken 187 times.
✗ Branch 4 (27→28) not taken.
✓ Branch 5 (27→47) taken 187 times.
187 if (cliOptions.targetArch == TARGET_WASM32 || cliOptions.targetArch == TARGET_WASM64) {
28 addLinkerFlag("-nostdlib");
29 addLinkerFlag("-Wl,--no-entry");
30 addLinkerFlag("-Wl,--export-all");
31 }
32 187 }
33
34 /**
35 * Start the linking process
36 */
37 187 void ExternalLinkerInterface::link() const {
38
1/2
✗ Branch 0 (3→4) not taken.
✓ Branch 1 (3→5) taken 187 times.
187 assert(!outputPath.empty());
39
40 // Build the linker command
41
1/2
✓ Branch 0 (5→6) taken 187 times.
✗ Branch 1 (5→104) not taken.
187 std::stringstream linkerCommandBuilder;
42
1/2
✓ Branch 0 (6→7) taken 187 times.
✗ Branch 1 (6→102) not taken.
187 const auto [linkerInvokerName, linkerInvokerPath] = FileUtil::findLinkerInvoker();
43
1/2
✓ Branch 0 (7→8) taken 187 times.
✗ Branch 1 (7→100) not taken.
187 linkerCommandBuilder << linkerInvokerPath;
44
1/2
✓ Branch 0 (8→9) taken 187 times.
✗ Branch 1 (8→100) not taken.
187 const auto [linkerName, linkerPath] = FileUtil::findLinker(cliOptions);
45
2/4
✓ Branch 0 (9→10) taken 187 times.
✗ Branch 1 (9→98) not taken.
✓ Branch 2 (10→11) taken 187 times.
✗ Branch 3 (10→98) not taken.
187 linkerCommandBuilder << " -fuse-ld=" << linkerPath;
46 // Append linker flags
47
2/2
✓ Branch 0 (18→13) taken 798 times.
✓ Branch 1 (18→19) taken 187 times.
985 for (const std::string &linkerFlag : linkerFlags)
48
2/4
✓ Branch 0 (14→15) taken 798 times.
✗ Branch 1 (14→77) not taken.
✓ Branch 2 (15→16) taken 798 times.
✗ Branch 3 (15→77) not taken.
798 linkerCommandBuilder << " " << linkerFlag;
49 // Append output path
50
3/6
✓ Branch 0 (19→20) taken 187 times.
✗ Branch 1 (19→98) not taken.
✓ Branch 2 (20→21) taken 187 times.
✗ Branch 3 (20→80) not taken.
✓ Branch 4 (21→22) taken 187 times.
✗ Branch 5 (21→78) not taken.
187 linkerCommandBuilder << " -o " << outputPath.string();
51 // Append object files
52
2/2
✓ Branch 0 (30→25) taken 717 times.
✓ Branch 1 (30→31) taken 187 times.
904 for (const std::string &objectFilePath : objectFilePaths)
53
2/4
✓ Branch 0 (26→27) taken 717 times.
✗ Branch 1 (26→81) not taken.
✓ Branch 2 (27→28) taken 717 times.
✗ Branch 3 (27→81) not taken.
717 linkerCommandBuilder << " " << objectFilePath;
54
55 // Print status message
56
1/2
✗ Branch 0 (31→32) not taken.
✓ Branch 1 (31→43) taken 187 times.
187 if (cliOptions.printDebugOutput) {
57 std::cout << "\nLinking with: " << linkerInvokerName << " (invoker) / " << linkerName << " (linker)"; // GCOV_EXCL_LINE
58 std::cout << "\nEmitting executable to path: " << outputPath.string() << "\n"; // GCOV_EXCL_LINE
59 }
60
61 // Call the linker
62
1/2
✓ Branch 0 (43→44) taken 187 times.
✗ Branch 1 (43→98) not taken.
187 Timer timer;
63
1/2
✓ Branch 0 (44→45) taken 187 times.
✗ Branch 1 (44→98) not taken.
187 timer.start();
64
1/2
✓ Branch 0 (45→46) taken 187 times.
✗ Branch 1 (45→98) not taken.
187 const std::string linkerCommand = linkerCommandBuilder.str();
65
1/2
✓ Branch 0 (46→47) taken 187 times.
✗ Branch 1 (46→96) not taken.
187 const auto [output, exitCode] = FileUtil::exec(linkerCommand);
66
1/2
✓ Branch 0 (47→48) taken 187 times.
✗ Branch 1 (47→94) not taken.
187 timer.stop();
67
68 // Check for linker error
69 if (exitCode != 0) // GCOV_EXCL_LINE
70 throw LinkerError(LINKER_ERROR, "Linker exited with non-zero exit code"); // GCOV_EXCL_LINE
71
72 // Print linker result if appropriate
73 if (cliOptions.printDebugOutput && !output.empty()) // GCOV_EXCL_LINE
74 std::cout << "Linking result: " << output << "\n\n"; // GCOV_EXCL_LINE
75
76 // Print link time
77 if (cliOptions.printDebugOutput) // GCOV_EXCL_LINE
78 std::cout << "Total link time: " << timer.getDurationMilliseconds() << " ms\n\n"; // GCOV_EXCL_LINE
79 187 }
80
81 /**
82 * Add another object file to be linked when calling 'link()'
83 *
84 * @param objectFilePath Path to the object file
85 */
86 753 void ExternalLinkerInterface::addObjectFilePath(const std::string &objectFilePath) { objectFilePaths.push_back(objectFilePath); }
87
88 /**
89 * Add another linker flag for the call to the linker executable
90 *
91 * @param flag Linker flag
92 */
93 799 void ExternalLinkerInterface::addLinkerFlag(const std::string &flag) { linkerFlags.push_back(flag); }
94
95 /**
96 * Add another source file to compile and link in (C or C++)
97 *
98 * @param additionalSource Additional source file
99 */
100 2 void ExternalLinkerInterface::addAdditionalSourcePath(std::filesystem::path additionalSource) {
101 // Check if the file exists
102 if (!exists(additionalSource)) { // GCOV_EXCL_LINE
103 const std::string msg = "The additional source file '" + additionalSource.string() + "' does not exist"; // GCOV_EXCL_LINE
104 throw CompilerError(IO_ERROR, msg); // GCOV_EXCL_LINE
105 } // GCOV_EXCL_LINE
106
107 // Add the file to the linker
108 2 additionalSource.make_preferred();
109
2/4
✓ Branch 0 (13→14) taken 2 times.
✗ Branch 1 (13→31) not taken.
✓ Branch 2 (14→15) taken 2 times.
✗ Branch 3 (14→29) not taken.
2 addObjectFilePath(additionalSource.string());
110 2 }
111
112 } // namespace spice::compiler
113