65int main(
int argc,
const char **argv) {
68 std::string inputFile;
69 std::string outputPathStr;
75 std::wstring targetTriple = L
"";
81 bool preserveIntermediateFiles =
false;
83 for (
int i = 1; i < argc; ++i) {
84 std::string arg = argv[i];
86 if (arg ==
"-o" || arg ==
"--output") {
88 outputPathStr = argv[++i];
90 std::cerr <<
"Error: " << arg <<
" requires a path argument.\n";
94 }
else if (arg ==
"--build-type") {
96 std::string typeStr = argv[++i];
100 std::cerr <<
"Error: Invalid build type '" << typeStr <<
"'. Valid types: executable, library.\n";
105 std::cerr <<
"Error: " << arg <<
" requires a type argument.\n";
109 }
else if (arg ==
"--build-mode") {
111 std::string modeStr = argv[++i];
115 std::cerr <<
"Error: Invalid build mode '" << modeStr <<
"'. Valid modes: debug, release.\n";
120 std::cerr <<
"Error: " << arg <<
" requires a mode argument.\n";
124 }
else if (arg ==
"--linker") {
126 std::string linkerStr = argv[++i];
131 std::cerr <<
"Error: Invalid linker type '" << linkerStr <<
"'. Valid types: cc, cl, none.\n";
136 std::cerr <<
"Error: " << arg <<
" requires a linker argument.\n";
140 }
else if (arg ==
"--clean" || arg ==
"--remove-intermediate") {
141 preserveIntermediateFiles =
false;
142 }
else if (arg ==
"-C" || arg ==
"--project-cache") {
146 std::cerr <<
"Error: " << arg <<
" requires a path argument.\n";
150 }
else if (arg ==
"-I" || arg ==
"--include") {
152 includeDirs.push_back(includeDir);
153 }
else if (arg ==
"-t" || arg ==
"--target") {
155 }
else if (arg ==
"--preserve-intermediate") {
156 preserveIntermediateFiles =
true;
157 }
else if (arg ==
"--linker-option" || arg ==
"-L") {
161 std::cerr <<
"Error: " << arg <<
" requires a flag argument.\n";
165 }
else if (arg ==
"--help" || arg ==
"-h") {
168 }
else if (arg ==
"--whereami" || arg ==
"-w") {
171 }
else if (arg ==
"--build-number") {
174 }
else if (arg ==
"-D" || arg ==
"--define") {
178 macroDefs.emplace_back(key, value);
180 std::cerr <<
"Error: " << arg <<
" requires two arguments.\n";
184 }
else if (arg ==
"-W" || arg ==
"--warning") {
186 std::string key = argv[++i];
189 std::cerr <<
"Error: " << arg <<
" requires one arguments.\n";
193 }
else if (arg ==
"-S" || arg ==
"--suppress") {
195 std::string key = argv[++i];
198 std::cerr <<
"Error: " << arg <<
" requires one arguments.\n";
202 }
else if (arg ==
"-E" || arg ==
"--error") {
204 std::string key = argv[++i];
207 std::cerr <<
"Error: " << arg <<
" requires one arguments.\n";
211 }
else if (!arg.starts_with(
"-")) {
212 if (arg.ends_with(
".hoshi") && inputFile.empty())
214 else if (arg.ends_with(
".hoshi") && !inputFile.empty()) {
215 std::cerr <<
"Warning: Multiple input files specified: " << inputFile <<
" and " << arg <<
"\n";
222 std::cerr <<
"Error: Unknown argument: " << arg <<
"\n";
229 if (inputFile.empty()) {
230 std::cerr <<
"Error: No input file provided.\n";
234 if (!fs::exists(inputFile)) {
235 std::cerr <<
"Error: Input file '" << inputFile <<
"' does not exist.\n";
238 if (!fs::is_regular_file(inputFile)) {
239 std::cerr <<
"Error: Input file '" << inputFile <<
"' is not a regular file.\n";
244 fs::path inputFilePath(inputFile);
246 fs::path outputBaseName;
248 if (outputPathStr.empty()) {
250 outputDir = fs::current_path();
251 outputBaseName = inputFilePath.stem();
253 fs::path specifiedOutputPath(outputPathStr);
254 if (specifiedOutputPath.has_filename()) {
256 outputDir = specifiedOutputPath.parent_path();
257 outputBaseName = specifiedOutputPath.stem();
259 outputDir = specifiedOutputPath;
260 outputBaseName = inputFilePath.stem();
266 if (!outputDir.empty() && !fs::exists(outputDir)) {
267 fs::create_directories(outputDir);
269 }
catch (
const fs::filesystem_error& e) {
270 std::cerr <<
"Error: Could not create output directory '" << outputDir.string() <<
"': " << e.what() <<
"\n";
275 fs::path yoiIRFile = outputDir / (outputBaseName.string() +
".yoi");
276 fs::path llvmIRFile = outputDir / (outputBaseName.string() +
".ll");
277 fs::path objectFile = outputDir / (outputBaseName.string() +
".o");
278 fs::path finalOutput = outputDir / (outputBaseName.string() +
getOutputExtension(buildType, targetPlatform));
281 std::vector<fs::path> intermediateFilesToClean;
282 if (!preserveIntermediateFiles) {
283 intermediateFilesToClean.push_back(yoiIRFile);
284 intermediateFilesToClean.push_back(llvmIRFile);
285 intermediateFilesToClean.push_back(objectFile);
291 std::shared_ptr<yoi::compilerContext> compilerCtx =
292 std::make_shared<yoi::compilerContext>();
294 compilerCtx->initializeSharedObjects();
298 .setBuildType(buildType)
300 .setBuildMode(buildMode)
302 .setTargetTriple(L
"")
303 .setUseObjectLinker(useObjectLinker)
304 .setPreserveIntermediateFiles(preserveIntermediateFiles)
305 .setImmediatelyClearupCache(projectCacheDir.empty())
316 for (
auto ¯o : macroDefs) {
317 compilerCtx->getBuildConfig()->marcos[macro.first] = macro.second;
322 auto entryModuleId = compilerCtx->compileModule(input);
323 compilerCtx->runOptimizer();
325 std::cout <<
"Linking Yoi IR modules...\n";
327 auto objectIRFile = linker.
link(compilerCtx, entryModuleId);
328 compilerCtx->setIRObjectFile(objectIRFile);
329 auto unifiedModule = objectIRFile->compiledModule;
331 auto yoiIRStr = unifiedModule->to_string();
332 std::error_code ec_yoi;
333 llvm::raw_fd_stream yoi_file(yoiIRFile.string(), ec_yoi);
335 throw std::runtime_error(
"Could not open YOI IR output file '" + yoiIRFile.string() +
"': " + ec_yoi.message());
341 std::cout <<
"Generating target object files...\n";
345 TIMER(
"Generating target object files", objectFileNames = llvmCodegen.
generate());
347 if (preserveIntermediateFiles) {
349 llvmCodegen.
dumpIR(L
"builtin", llvmIRFile.string());
354 switch (useObjectLinker) {
377 std::cout <<
"Object linking skipped (--linker none).\n";
379 std::cout <<
"Compilation successful!\n";
381 if (compilerCtx->getBuildConfig()->immediatelyClearupCache) {
382 std::error_code ec_remove;
383 std::filesystem::remove_all(compilerCtx->getBuildConfig()->buildCachePath, ec_remove);
385 std::cerr <<
"Warning: Could not remove cache file '" <<
yoi::wstring2string(compilerCtx->getBuildConfig()->buildCachePath) <<
"': " << ec_remove.message() <<
"\n";
388 }
catch (
const std::runtime_error &e) {
389 std::cerr <<
"Error: " << e.what() << std::endl;
396 if (!preserveIntermediateFiles && exitCode == 0) {
397 for (
const auto& file : intermediateFilesToClean) {
398 std::error_code ec_remove;
399 fs::remove(file, ec_remove);
401 std::cerr <<
"Warning: Could not remove intermediate file '" << file.string() <<
"': " << ec_remove.message() <<
"\n";
404 }
else if (preserveIntermediateFiles) {
405 std::cout <<
"Intermediate files preserved.\n";
std::string getOutputExtension(yoi::IRBuildConfig::BuildType type, std::wstring platform)
void printUsage(const char *programName)