hoshi-lang dev
Yet another programming language
Loading...
Searching...
No Matches
ccObjectLinker.cpp
Go to the documentation of this file.
1//
2// Created by XIaokang00010 on 2025/7/31.
3//
4
5#include "ccObjectLinker.h"
6#include "compiler/ir/IR.h"
7#include "share/def.hpp"
8#include <cstring>
9#include <sstream>
10#include <filesystem>
11#include <string>
12
13namespace yoi {
14
15 ccObjectLinker::ccObjectLinker(const yoi::vec<yoi::wstr> &objectPaths, const std::shared_ptr<IRBuildConfig> &config)
16 : ObjectLinker(objectPaths, config) {
17 this->setLinkerPath(L"");
18 }
19
20 bool ccObjectLinker::commandExists(const std::string& commandName) {
21 const char* path_env = std::getenv("PATH");
22 if (!path_env) {
23 return false; // PATH not set
24 }
25
26 std::string path_str(path_env);
27 std::istringstream iss(path_str);
28 std::string path_segment;
29
30#ifdef _WIN32
31 const char path_delimiter = ';';
32 const std::string executable_extension = ".exe";
33#else
34 const char path_delimiter = ':';
35 const std::string executable_extension;
36#endif
37
38 // iterate through each segment in PATH
39 while (std::getline(iss, path_segment, path_delimiter)) {
40 std::filesystem::path full_path = std::filesystem::path(path_segment) / (commandName + executable_extension);
41
42 // check if the file exists and is a regular file (i.e., not a directory)
43 if (std::filesystem::exists(full_path) && std::filesystem::is_regular_file(full_path)) {
44 return true;
45 }
46 }
47 return false;
48 }
49
50
52 if (commandExists("cc")) {
53 setLinkerPath(L"cc");
54 } else if (commandExists("gcc")) {
55 setLinkerPath(L"gcc");
56 } else if (commandExists("clang")) {
57 setLinkerPath(L"clang");
58 }
59 else {
60 throw std::runtime_error("ccObjectLinker: 'cc', 'gcc', or 'clang' not found in system PATH. Cannot setup linker.");
61 }
62 return *this;
63 }
64
66 if (this->getLinkerPath().empty()) {
67 throw std::runtime_error("ccObjectLinker: Linker path not set. Call searchAndSetupLinker() first.");
68 }
69 if (this->getObjectPaths().empty()) {
70 throw std::runtime_error("ccObjectLinker: Object file path not set.");
71 }
72
73 std::string command = "\"" + yoi::wstring2string(this->getLinkerPath()) + "\"";
74 for (const auto &objectPath : this->getObjectPaths()) {
75 command += " \"";
76 command += yoi::wstring2string(objectPath) + "\"";
77 }
78
79 // add additional linking files
80 if (strcmp(YOI_PLATFORM, "darwin") != 0)
81 // if the platform is not darwin, we need to add -Wl,--start-group and -Wl,--end-group to link as groups
82 command += " -Wl,--start-group";
83 for (const auto &file : this->getConfig()->additionalLinkingFiles) {
84 // link as groups
85 command += " \"" + yoi::wstring2string(file) + "\"";
86 }
87 if (strcmp(YOI_PLATFORM, "darwin") != 0)
88 command += " -Wl,--end-group";
89
90 command += " -o \"";
91 command += yoi::wstring2string(outputPath) + "\"";
92
93 // add Elysia runtime path and library
94 if (!this->getElysiaRuntimePath().empty()) {
95 // ensure the elysiaRuntimePath exists as a directory
96 std::filesystem::path elysia_path_fs(this->getElysiaRuntimePath());
97 if (!std::filesystem::exists(elysia_path_fs) || !std::filesystem::is_directory(elysia_path_fs)) {
98 std::string error_msg = "ccObjectLinker: Elysia runtime path does not exist or is not a directory: " +
100 throw std::runtime_error(error_msg);
101 }
102
103 command += " -L\""; // add library search path
104 command += yoi::wstring2string(this->getElysiaRuntimePath()) + "\"";
105 command += " -lelysia_runtime";
106 }
107
108 if (this->getConfig()->buildType == IRBuildConfig::BuildType::library) {
109 command += " -shared"; // build a shared library
110 }
111
112 // synchronize the release/debug
113 if (this->getConfig()->buildMode == IRBuildConfig::BuildMode::debug) {
114 command += " -g";
115 }
116#ifdef _WIN32
117 command += " -mconsole"; // fuck argc, argv
118 replace_all(command, std::string("\""), std::string("\\\""));
119 command = "powershell.exe -Command \"&" + command + "\""; // fuck win32 command line
120#endif
121
122 int result = std::system(command.c_str());
123 if (result != 0) {
124 std::string error_msg = "ccObjectLinker: Linker command failed with exit code " + std::to_string(result) + ". Command: " + command;
125 throw std::runtime_error(error_msg);
126 }
127 return *this;
128 }
129
130} // namespace yoi
std::shared_ptr< IRBuildConfig > getConfig() const
ObjectLinker & setLinkerPath(const yoi::wstr &linkerPath)
yoi::wstr getLinkerPath() const
yoi::vec< yoi::wstr > getObjectPaths() const
yoi::wstr getElysiaRuntimePath() const
bool commandExists(const std::string &command)
ccObjectLinker(const yoi::vec< yoi::wstr > &objectPaths, const std::shared_ptr< IRBuildConfig > &config)
ObjectLinker & link(const yoi::wstr &outputPath) override
ObjectLinker & searchAndSetupLinker() override
#define YOI_PLATFORM
Definition def.hpp:31
std::string wstring2string(const std::wstring &v)
Definition def.cpp:184
void replace_all(string_t &str, const string_t &from, const string_t &to)
Definition def.hpp:368
std::vector< t > vec
Definition def.hpp:53
std::wstring wstr
Definition def.hpp:48