GCC Code Coverage Report


Directory: ../
File: src/linker/ExternalLinkerInterface.cpp
Date: 2024-11-22 23:10:59
Exec Total Coverage
Lines: 29 33 87.9%
Functions: 5 5 100.0%
Branches: 35 80 43.8%

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