Skip to content
This repository was archived by the owner on Jun 26, 2023. It is now read-only.

Commit 1ecae6d

Browse files
authored
feat: Add initial implementation for the generation of an executable file (#92)
* refactor: Fix llvm usage with memory leak * Add initial option for generating executable
1 parent 8ff3714 commit 1ecae6d

16 files changed

+218
-69
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ bin/*
4545

4646
# arx
4747
arxc
48+
*.arxc
49+
*.arx.o
4850

4951
# IDE
5052
.vscode

.makim.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ groups:
7878
- target: build.release
7979
args:
8080
build-type: "debug"
81-
extras: "-Db_coverage=true -Doptimization=0" # -Db_sanitize=address
81+
extras: "-Db_coverage=true -Doptimization=0" # -Db_sanitize=address
8282
clean: {{ args.clean }}
8383
asan-options: "fast_unwind_on_malloc=0:verbosity=2:log_threads=1"
8484
lsan-options: "fast_unwind_on_malloc=0:verbosity=2:log_threads=1"
@@ -204,7 +204,7 @@ groups:
204204
# another options: halt_on_error=true
205205
# it could be a useful flag: -fsanitize-recover
206206
export LSAN_OPTIONS=verbosity=2:log_threads=1
207-
export ASAN_OPTIONS=verbosity=2:check_initialization_order=1:detect_leaks=1
207+
export ASAN_OPTIONS=verbosity=2:check_initialization_order=1:detect_leaks=1:fast_unwind_on_malloc=0
208208
209209
if [[ "{{ args.debug }}" == "True" ]]; then
210210
GDB="gdb --args"
@@ -216,13 +216,14 @@ groups:
216216
# load utils functions
217217
. "${TEST_DIR_PATH}/scripts/utils.sh"
218218
219-
ARX="${GDB} ./build/arx"
219+
ARX="${GDB} ./build/arx --build-lib"
220220
MAIN_EXE="${TMP_DIR}/main"
221221
222222
LD_LIBRARY_PATH=${CONDA_PREFIX}/lib:$LD_LIBRARY_PATH
223223
export LD_LIBRARY_PATH
224224
225-
CLANG_EXTRAS="$(llvm-config --cxxflags)"
225+
CLANG_EXTRAS="-fno-omit-frame-pointer"
226+
CLANG_EXTRAS="${CLANG_EXTRAS} $(llvm-config --cxxflags)"
226227
CLANG_EXTRAS="${CLANG_EXTRAS} $(llvm-config --ldflags --libs core executionengine interpreter analysis native bitwriter)"
227228
CLANG_EXTRAS="${CLANG_EXTRAS} $(pkg-config --cflags --libs arrow-glib)"
228229
CLANG_EXTRAS=$(echo "${CLANG_EXTRAS}" | sed s/-std=c++14/-std=c++20/g)
@@ -248,7 +249,6 @@ groups:
248249
echo ">>> RUN THE PROGRAM:"
249250
chmod +x ${MAIN_EXE}
250251
${GDB} ${MAIN_EXE}
251-
break
252252
done
253253
254254
gen-ast:

meson.build

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ project('arx', 'cpp', 'c',
99

1010
add_global_arguments(
1111
'-Wpedantic',
12-
'-Wno-c++98-compat-pedantic',
12+
# '-Wno-c++98-compat-pedantic',
1313
'-Wno-padded',
1414
'-Wno-missing-prototypes',
1515
'-Wshadow',
@@ -33,10 +33,19 @@ PROJECT_PATH = meson.source_root()
3333

3434
cxx = meson.get_compiler('cpp')
3535

36+
llvm_modules = [
37+
'core',
38+
'executionengine',
39+
'object',
40+
'orcjit',
41+
'support',
42+
'native',
43+
]
44+
3645
deps = [
3746
dependency('arrow'),
3847
dependency('arrow-glib'),
39-
dependency('llvm', version : '>=14.0.0'),
48+
dependency('llvm', version : '>=15.0.0', modules : llvm_modules),
4049
dependency('CLI11'),
4150
dependency('threads'),
4251
dependency('glog'),

src/codegen/arx-llvm.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,5 @@ llvm::Type* ArxLLVM::DOUBLE_TYPE;
2222
llvm::Type* ArxLLVM::FLOAT_TYPE;
2323
llvm::Type* ArxLLVM::INT8_TYPE;
2424
llvm::Type* ArxLLVM::INT32_TYPE;
25+
26+
extern bool IS_BUILD_LIB = false; // default value

src/codegen/arx-llvm.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,5 @@ class ArxLLVM {
2525
static llvm::Type* INT8_TYPE;
2626
static llvm::Type* INT32_TYPE;
2727
};
28+
29+
extern bool IS_BUILD_LIB;

src/codegen/ast-to-llvm-ir.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ auto ASTToLLVMIRVisitor::Initialize() -> void {
297297
*
298298
* @param ast The AST tree object.
299299
*/
300-
auto compile_llvm_ir(TreeAST& ast) -> void {
300+
auto compile_llvm_ir(TreeAST& ast) -> int {
301301
auto codegen = std::make_unique<ASTToLLVMIRVisitor>(ASTToLLVMIRVisitor());
302302

303303
Lexer::getNextToken();
@@ -356,19 +356,19 @@ auto compile_llvm_ir(TreeAST& ast) -> void {
356356

357357
// Print out all of the generated code.
358358
ArxLLVM::module->print(llvm::errs(), nullptr);
359+
360+
return 0;
359361
}
360362

361363
/**
362364
* @brief Open the Arx shell.
363365
*
364366
*/
365-
auto open_shell_llvm_ir() -> void {
367+
auto open_shell_llvm_ir() -> int {
366368
// Prime the first token.
367369
fprintf(stderr, "Arx %s \n", ARX_VERSION.c_str());
368370
fprintf(stderr, ">>> ");
369371

370372
auto ast = std::make_unique<TreeAST>(TreeAST());
371-
compile_llvm_ir(*ast);
372-
373-
exit(0);
373+
return compile_llvm_ir(*ast);
374374
}

src/codegen/ast-to-llvm-ir.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
#include "codegen/ast-to-object.h"
3232
#include "parser.h"
3333

34-
auto compile_llvm_ir(TreeAST&) -> void;
35-
auto open_shell_llvm_ir() -> void;
34+
auto compile_llvm_ir(TreeAST&) -> int;
35+
auto open_shell_llvm_ir() -> int;
3636

3737
class ASTToLLVMIRVisitor : public ASTToObjectVisitor {
3838
public:

src/codegen/ast-to-object.cpp

Lines changed: 99 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,17 @@
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
@@ -26,25 +39,32 @@
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

4450
namespace 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+
4868
extern std::string INPUT_FILE;
4969
extern std::string OUTPUT_FILE;
5070
extern 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
}

src/codegen/ast-to-object.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ namespace llvm {
2222
class Value;
2323
}
2424

25-
auto compile_object(TreeAST&) -> void;
26-
auto open_shell_object() -> void;
25+
auto compile_object(TreeAST&) -> int;
26+
auto open_shell_object() -> int;
2727

2828
class ASTToObjectVisitor : public Visitor {
2929
public:

src/codegen/ast-to-stdout.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ void ASTToOutputVisitor::visit(FunctionAST& expr) {
233233
std::cout << this->indentation() << ")" << std::endl;
234234
}
235235

236-
auto print_ast(TreeAST& ast) -> void {
236+
auto print_ast(TreeAST& ast) -> int {
237237
auto visitor_print =
238238
std::make_unique<ASTToOutputVisitor>(ASTToOutputVisitor());
239239

@@ -246,4 +246,5 @@ auto print_ast(TreeAST& ast) -> void {
246246
}
247247

248248
std::cout << "]" << std::endl;
249+
return 0;
249250
}

0 commit comments

Comments
 (0)