1- #include " codegen/ast-to-object.h" // for ASTToObjectVisitor, compile_o...
1+ #include < cassert> // for assert
2+ #include < cstdio> // for fprintf, stderr, fputc
3+ #include < cstdlib> // for exit
4+ #include < fstream> // for operator<<
5+ #include < iostream>
6+ #include < map> // for map, operator==, _Rb_tree_ite...
7+ #include < memory> // for unique_ptr, allocator, make_u...
8+ #include < numeric> // for accumulate
9+ #include < sstream>
10+ #include < string> // for string, operator<=>, operator+
11+ #include < system_error> // for error_code
12+ #include < utility> // for pair, move
13+ #include < vector> // for vector
14+
215#include < glog/logging.h> // for COMPACT_GOOGLE_LOG_INFO, LOG
316#include < llvm/ADT/APFloat.h> // for APFloat
417#include < llvm/ADT/iterator_range.h> // for iterator_range
2639#include < llvm/Support/TargetSelect.h> // for InitializeAllAsmParsers, Init...
2740#include < llvm/Target/TargetMachine.h> // for TargetMachine
2841#include < llvm/Target/TargetOptions.h> // for TargetOptions
29- #include < cassert> // for assert
30- #include < cstdio> // for fprintf, stderr, fputc
31- #include < cstdlib> // for exit
32- #include < fstream> // for operator<<
33- #include < map> // for map, operator==, _Rb_tree_ite...
34- #include < memory> // for unique_ptr, allocator, make_u...
35- #include < string> // for string, operator<=>, operator+
36- #include < system_error> // for error_code
37- #include < utility> // for pair, move
38- #include < vector> // for vector
39- #include " codegen/arx-llvm.h" // for ArxLLVM
40- #include " error.h" // for LogErrorV
41- #include " lexer.h" // for Lexer
42- #include " parser.h" // for PrototypeAST, ExprAST, ForExp...
42+
43+ #include " codegen/arx-llvm.h" // for ArxLLVM
44+ #include " codegen/ast-to-object.h" // for ASTToObjectVisitor, compile_o...
45+ #include " error.h" // for LogErrorV
46+ #include " io.h" // for ArxFile
47+ #include " lexer.h" // for Lexer
48+ #include " parser.h" // for PrototypeAST, ExprAST, ForExp...
4349
4450namespace llvm {
4551 class Value ;
4652}
4753
54+ std::string string_join (
55+ const std::vector<std::string>& elements, const std::string& delimiter) {
56+ if (elements.empty ()) {
57+ return " " ;
58+ }
59+
60+ std::string str;
61+ for (auto v : elements) {
62+ str += v + delimiter;
63+ }
64+ str = str.substr (0 , str.size () - delimiter.size ());
65+ return str;
66+ }
67+
4868extern std::string INPUT_FILE;
4969extern std::string OUTPUT_FILE;
5070extern std::string ARX_VERSION;
@@ -635,7 +655,7 @@ extern "C" DLLEXPORT auto printd(double X) -> double {
635655 *
636656 * @param tree_ast The AST tree object.
637657 */
638- auto compile_object (TreeAST& tree_ast) -> void {
658+ auto compile_object (TreeAST& tree_ast) -> int {
639659 auto codegen = std::make_unique<ASTToObjectVisitor>(ASTToObjectVisitor ());
640660
641661 Lexer::getNextToken ();
@@ -669,7 +689,7 @@ auto compile_object(TreeAST& tree_ast) -> void {
669689 // TargetRegistry or we have a bogus target triple.
670690 if (!Target) {
671691 llvm::errs () << Error;
672- exit ( 1 ) ;
692+ return 1 ;
673693 }
674694
675695 auto CPU = " generic" ;
@@ -692,40 +712,95 @@ auto compile_object(TreeAST& tree_ast) -> void {
692712 std::error_code EC;
693713
694714 if (OUTPUT_FILE == " " ) {
695- OUTPUT_FILE = " ./output .o" ;
715+ OUTPUT_FILE = INPUT_FILE + " .o" ;
696716 }
697717
698718 llvm::raw_fd_ostream dest (OUTPUT_FILE, EC, llvm::sys::fs::OF_None);
699719
700720 if (EC) {
701721 llvm::errs () << " Could not open file: " << EC.message ();
702- exit ( 1 ) ;
722+ return 1 ;
703723 }
704724
705725 llvm::legacy::PassManager pass;
726+
706727 auto FileType = llvm::CGFT_ObjectFile;
707728
708729 if (TheTargetMachine->addPassesToEmitFile (pass, dest, nullptr , FileType)) {
709730 llvm::errs () << " TheTargetMachine can't emit a file of this type" ;
710- exit ( 1 ) ;
731+ return 1 ;
711732 }
712733
713734 pass.run (*ArxLLVM::module );
714735 dest.flush ();
736+
737+ if (IS_BUILD_LIB) {
738+ return 0 ;
739+ }
740+
741+ // generate an executable file
742+
743+ std::string linker_path = " clang++" ;
744+ std::string executable_path = INPUT_FILE + " c" ;
745+ // note: it just have a purpose to demonstrate an initial implementation
746+ // it will be improved in a follow-up PR
747+ std::string content =
748+ " #include <iostream>\n "
749+ " int main() {\n "
750+ " std::cout << \" ARX[WARNING]: "
751+ " This is an empty executable file\" << std::endl;\n "
752+ " }\n " ;
753+
754+ std::string main_cpp_path = ArxFile::create_tmp_file (content);
755+
756+ if (main_cpp_path == " " ) {
757+ llvm::errs () << " ARX[FAIL]: Executable file was not created." ;
758+ return 1 ;
759+ }
760+
761+ /* Example (running it from a shell prompt):
762+ clang++ \
763+ ${CLANG_EXTRAS} \
764+ ${DEBUG_FLAGS} \
765+ -fPIC \
766+ -std=c++20 \
767+ "${TEST_DIR_PATH}/main-objects/${test_name}.cpp" \
768+ ${OBJECT_FILE} \
769+ -o "${TMP_DIR}/main"
770+ */
771+
772+ std::vector<std::string> compiler_args{
773+ " -fPIC" , " -std=c++20" , main_cpp_path, OUTPUT_FILE, " -o" , executable_path};
774+
775+ // Add any additional compiler flags or include paths as needed
776+ // compiler_args.push_back("-I/path/to/include");
777+
778+ std::string compiler_cmd =
779+ linker_path + " " + string_join (compiler_args, " " );
780+
781+ std::cout << " ARX[INFO]: " << compiler_cmd << std::endl;
782+ int compile_result = system (compiler_cmd.c_str ());
783+
784+ // ArxFile::delete_file(main_cpp_path);
785+
786+ if (compile_result != 0 ) {
787+ llvm::errs () << " failed to compile and link object file" ;
788+ exit (1 );
789+ }
790+
791+ return 0 ;
715792}
716793
717794/* *
718795 * @brief Open the Arx shell.
719796 *
720797 */
721- auto open_shell_object () -> void {
798+ auto open_shell_object () -> int {
722799 // Prime the first token.
723800 fprintf (stderr, " Arx %s \n " , ARX_VERSION.c_str ());
724801 fprintf (stderr, " >>> " );
725802
726803 auto ast = std::make_unique<TreeAST>(TreeAST ());
727804
728- compile_object (*ast);
729-
730- exit (0 );
805+ return compile_object (*ast);
731806}
0 commit comments