| chigraph master Systems programming language written for beginners in LLVM

LibCLocator.cpp
1
2 #include "chi/Support/LibCLocator.hpp"
3
4 // This requires 3 separate implementations--one for windows, one for linux, and one for macOS.
5
6 namespace fs = boost::filesystem;
7
8 #if defined __linux__ || defined __APPLE__
9
10 #include <boost/algorithm/string/classification.hpp>
11 #include <boost/algorithm/string/split.hpp>
12 #include <cstdlib>
13
14 #include "chi/Support/Result.hpp"
15 #include "chi/Support/Subprocess.hpp"
16
17 namespace chi {
18
19 // The linux implementation finds gcc and runs what's basically gcc -xc -E -v - < /dev/null which
20 // prints out the search paths.
21
22 Result stdCIncludePaths(std::vector<boost::filesystem::path>& toFill) {
23 Result res;
24
25 // first see if CHI_STDC_INCLUDE_PATH is defined in the environment
26 auto envIncPath = std::getenv("CHI_STDC_INCLUDE_PATH");
27 if (envIncPath != nullptr) {
28 std::string envIncPathStr = envIncPath;
29
30 std::vector<std::string> parsedOut;
31 boost::algorithm::split(parsedOut, envIncPathStr, boost::algorithm::is_any_of(":"));
32
33 std::transform(parsedOut.begin(), parsedOut.end(), std::back_inserter(toFill),
34 [](auto p) { return fs::path{p}; });
35 return res;
36 }
37
38 // find gcc
39 std::string colonSeparatedPath = std::getenv("PATH");
40 std::vector<std::string> paths;
41 boost::algorithm::split(paths, colonSeparatedPath, boost::algorithm::is_any_of(":"));
42
43 fs::path gccPath;
44 for (const auto& possiblePath : paths) {
45 auto pathToCheck = fs::path{possiblePath} / "gcc";
46
47 if (fs::is_regular_file(pathToCheck) || fs::is_symlink(pathToCheck)) {
48 gccPath = pathToCheck;
49 break;
50 }
51 }
52
53 if (gccPath.empty()) {
54 res.addEntry("EUKN", "Failed to find gcc in path", {{}});
55 return res;
56 }
57
58 // run it!
59 Subprocess sub{gccPath};
60 sub.setArguments({"-xc", "-E", "-v", "-"});
61
62 // the spicy output is in stderr
63 std::string stdErrData;
64 sub.attachStringToStdErr(stdErrData);
65
66 res += sub.start();
67 if (!res) { return res; }
68
69 res += sub.closeStdIn();
70 if (!res) { return res; }
71
72 int err = sub.exitCode();
73 if (err != 0) {
74 res.addEntry("EUKN", "Failed to run GCC", {{"Error code", err}, {"Stderr", stdErrData}});
75 return res;
76 }
77
78 // parse the stderr
79 // it looks something like this:
80 //
81 // <random stuff>
82 // #include <...> search starts here:
83 // <include path>
84 // ...
85 // End of search list.
86
87 // split it into lines
88 std::vector<std::string> stdErrLines;
89 boost::algorithm::split(stdErrLines, stdErrData, boost::algorithm::is_any_of("\n"));
90
91 // find #include <...> search starts here:
92 auto iter =
93 std::find(stdErrLines.begin(), stdErrLines.end(), "#include <...> search starts here:");
94 if (iter == stdErrLines.end()) {
95 res.addEntry("EUKN", "Failed to find \"#include <...> search starts here:\" in gcc stderr",
96 {{"Stderr", stdErrData}});
97 return res;
98 }
99
100 // start appending
101 ++iter;
102
103 for (; iter != stdErrLines.end() && *iter != "End of search list."; ++iter) {
104 assert((*iter)[0] == ' ');
105 std::string incPath = iter->substr(1); // remove the first char, it's gonna be a space
106
107 // append it to `toFill`
108 if (fs::is_directory(incPath)) { toFill.push_back(incPath); }
109 }
110
111 return res;
112 }
113 } // chi
114
115 #elif defined WIN32
116
117 // it actually works fine without anyting! yay!
118
119 #include "chi/Support/Result.hpp"
120
121 namespace chi {
122
123 Result stdCIncludePaths(std::vector<boost::filesystem::path>& toFill) { return {}; }
124
125 } // namespace chi
126
127 #else
128
129 #endif
Subprocess.hpp
Result.hpp
Defines the Result class and related functions.
chi::stdCIncludePaths
Result stdCIncludePaths(std::vector< boost::filesystem::path > &toFill)
Gets the location of the standard C library to include.
LibCLocator.hpp
chi
The namespace where chigraph lives.
Definition: BitcodeParser.hpp:12