63int main(
int argc,
const char **argv) {
66 std::string inputFile;
67 std::string outputPathStr;
77 bool preserveIntermediateFiles =
false;
79 for (
int i = 1; i < argc; ++i) {
80 std::string arg = argv[i];
82 if (arg ==
"-o" || arg ==
"--output") {
84 outputPathStr = argv[++i];
86 std::cerr <<
"Error: " << arg <<
" requires a path argument.\n";
90 }
else if (arg ==
"--build-type") {
92 std::string typeStr = argv[++i];
96 std::cerr <<
"Error: Invalid build type '" << typeStr <<
"'. Valid types: executable, library.\n";
101 std::cerr <<
"Error: " << arg <<
" requires a type argument.\n";
105 }
else if (arg ==
"--build-mode") {
107 std::string modeStr = argv[++i];
111 std::cerr <<
"Error: Invalid build mode '" << modeStr <<
"'. Valid modes: debug, release.\n";
116 std::cerr <<
"Error: " << arg <<
" requires a mode argument.\n";
120 }
else if (arg ==
"--linker") {
122 std::string linkerStr = argv[++i];
127 std::cerr <<
"Error: Invalid linker type '" << linkerStr <<
"'. Valid types: cc, cl, none.\n";
132 std::cerr <<
"Error: " << arg <<
" requires a linker argument.\n";
136 }
else if (arg ==
"--clean" || arg ==
"--remove-intermediate") {
137 preserveIntermediateFiles =
false;
138 }
else if (arg ==
"-C" || arg ==
"--project-cache") {
142 std::cerr <<
"Error: " << arg <<
" requires a path argument.\n";
146 }
else if (arg ==
"-I" || arg ==
"--include") {
148 includeDirs.push_back(includeDir);
149 }
else if (arg ==
"--preserve-intermediate") {
150 preserveIntermediateFiles =
true;
151 }
else if (arg ==
"--help" || arg ==
"-h") {
154 }
else if (arg ==
"--whereami" || arg ==
"-w") {
157 }
else if (arg ==
"--build-number") {
160 }
else if (arg ==
"-D" || arg ==
"--define") {
164 macroDefs.emplace_back(key, value);
166 std::cerr <<
"Error: " << arg <<
" requires two arguments.\n";
170 }
else if (arg ==
"-W" || arg ==
"--warning") {
172 std::string key = argv[++i];
175 std::cerr <<
"Error: " << arg <<
" requires one arguments.\n";
179 }
else if (arg ==
"-S" || arg ==
"--suppress") {
181 std::string key = argv[++i];
184 std::cerr <<
"Error: " << arg <<
" requires one arguments.\n";
188 }
else if (arg ==
"-E" || arg ==
"--error") {
190 std::string key = argv[++i];
193 std::cerr <<
"Error: " << arg <<
" requires one arguments.\n";
197 }
else if (!arg.starts_with(
"-")) {
198 if (arg.ends_with(
".hoshi") && inputFile.empty())
200 else if (arg.ends_with(
".hoshi") && !inputFile.empty()) {
201 std::cerr <<
"Warning: Multiple input files specified: " << inputFile <<
" and " << arg <<
"\n";
208 std::cerr <<
"Error: Unknown argument: " << arg <<
"\n";
215 if (inputFile.empty()) {
216 std::cerr <<
"Error: No input file provided.\n";
220 if (!fs::exists(inputFile)) {
221 std::cerr <<
"Error: Input file '" << inputFile <<
"' does not exist.\n";
224 if (!fs::is_regular_file(inputFile)) {
225 std::cerr <<
"Error: Input file '" << inputFile <<
"' is not a regular file.\n";
230 fs::path inputFilePath(inputFile);
232 fs::path outputBaseName;
234 if (outputPathStr.empty()) {
236 outputDir = fs::current_path();
237 outputBaseName = inputFilePath.stem();
239 fs::path specifiedOutputPath(outputPathStr);
240 if (specifiedOutputPath.has_filename()) {
242 outputDir = specifiedOutputPath.parent_path();
243 outputBaseName = specifiedOutputPath.stem();
245 outputDir = specifiedOutputPath;
246 outputBaseName = inputFilePath.stem();
252 if (!outputDir.empty() && !fs::exists(outputDir)) {
253 fs::create_directories(outputDir);
255 }
catch (
const fs::filesystem_error& e) {
256 std::cerr <<
"Error: Could not create output directory '" << outputDir.string() <<
"': " << e.what() <<
"\n";
261 fs::path yoiIRFile = outputDir / (outputBaseName.string() +
".yoi");
262 fs::path llvmIRFile = outputDir / (outputBaseName.string() +
".ll");
263 fs::path objectFile = outputDir / (outputBaseName.string() +
".o");
264 fs::path finalOutput = outputDir / (outputBaseName.string() +
getOutputExtension(buildType, targetPlatform));
267 std::vector<fs::path> intermediateFilesToClean;
268 if (!preserveIntermediateFiles) {
269 intermediateFilesToClean.push_back(yoiIRFile);
270 intermediateFilesToClean.push_back(llvmIRFile);
271 intermediateFilesToClean.push_back(objectFile);
277 std::shared_ptr<yoi::compilerContext> compilerCtx =
278 std::make_shared<yoi::compilerContext>();
280 compilerCtx->initializeSharedObjects();
284 .setBuildType(buildType)
286 .setBuildMode(buildMode)
288 .setUseObjectLinker(useObjectLinker)
289 .setPreserveIntermediateFiles(preserveIntermediateFiles)
290 .setImmediatelyClearupCache(projectCacheDir.empty())
300 for (
auto ¯o : macroDefs) {
301 compilerCtx->getBuildConfig()->marcos[macro.first] = macro.second;
306 auto entryModuleId = compilerCtx->compileModule(input);
307 compilerCtx->runOptimizer();
309 std::cout <<
"Linking Yoi IR modules...\n";
311 auto objectIRFile = linker.
link(compilerCtx, entryModuleId);
312 compilerCtx->setIRObjectFile(objectIRFile);
313 auto unifiedModule = objectIRFile->compiledModule;
315 auto yoiIRStr = unifiedModule->to_string();
316 std::error_code ec_yoi;
317 llvm::raw_fd_stream yoi_file(yoiIRFile.string(), ec_yoi);
319 throw std::runtime_error(
"Could not open YOI IR output file '" + yoiIRFile.string() +
"': " + ec_yoi.message());
325 std::cout <<
"Generating target object files...\n";
329 TIMER(
"Generating target object files", objectFileNames = llvmCodegen.
generate());
331 if (preserveIntermediateFiles) {
333 llvmCodegen.
dumpIR(L
"builtin", llvmIRFile.string());
338 switch (useObjectLinker) {
361 std::cout <<
"Object linking skipped (--linker none).\n";
363 std::cout <<
"Compilation successful!\n";
365 if (compilerCtx->getBuildConfig()->immediatelyClearupCache) {
366 std::error_code ec_remove;
367 std::filesystem::remove_all(compilerCtx->getBuildConfig()->buildCachePath, ec_remove);
369 std::cerr <<
"Warning: Could not remove cache file '" <<
yoi::wstring2string(compilerCtx->getBuildConfig()->buildCachePath) <<
"': " << ec_remove.message() <<
"\n";
372 }
catch (
const std::logic_error &e) {
373 std::cerr <<
"Error: " << e.what() << std::endl;
380 if (!preserveIntermediateFiles && exitCode == 0) {
381 for (
const auto& file : intermediateFilesToClean) {
382 std::error_code ec_remove;
383 fs::remove(file, ec_remove);
385 std::cerr <<
"Warning: Could not remove intermediate file '" << file.string() <<
"': " << ec_remove.message() <<
"\n";
388 }
else if (preserveIntermediateFiles) {
389 std::cout <<
"Intermediate files preserved.\n";
std::string getOutputExtension(yoi::IRBuildConfig::BuildType type, std::wstring platform)
void printUsage(const char *programName)