Skip to content

Commit 92f08ad

Browse files
committed
[#102] Made compilation and linking more robust on macOS
1 parent 2352f8f commit 92f08ad

File tree

3 files changed

+59
-31
lines changed

3 files changed

+59
-31
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ The only dependencies that must be installed are Clang and Python.
3939

4040
To install Clang on Windows you must install Visual Studio, follow this [steps](https://learn.microsoft.com/en-us/cpp/build/vscpp-step-0-installation?view=msvc-170), and when choosing components also select Clang.
4141

42+
### macOs
43+
44+
Also, on macOS at least the prebuilt version of LLVM needs [zstd](https://formulae.brew.sh/formula/zstd) to be installed.
45+
4246
## Building
4347

4448
To get LLVM you can run `get_llvm.py`. This script download LLVM prebuilt binaries, extract them and save them in `deps` inside `llvm`.

build.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,9 @@ def need_to_recompile():
6868
if not os.path.exists(os.path.join('cache', file.split('.')[0] + get_object_file_extension())):
6969
return True
7070

71-
# Check if source file was edited after creation of diamond executable
72-
if os.path.getmtime(os.path.join('src', file)) > os.path.getmtime(get_name()):
73-
return True
71+
# Check if source file was edited after creation of diamond executable
72+
if os.path.getmtime(os.path.join('src', file)) > os.path.getmtime(get_name()):
73+
return True
7474

7575
# Build
7676
# -----

src/codegen/codegen.cpp

Lines changed: 52 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ void codegen::print_assembly(ast::Ast& ast, std::string program_name) {
5151

5252
// Generate assembly
5353
llvm::legacy::PassManager pass;
54-
54+
5555
auto& llvm_outs = llvm::outs();
5656
if (TargetMachine->addPassesToEmitFile(pass, llvm_outs, nullptr, llvm::CGFT_AssemblyFile)) {
5757
llvm::errs() << "TargetMachine can't emit a file of this type";
@@ -178,7 +178,7 @@ static void link(std::string executable_name, std::string object_file_name, std:
178178
bool result = lld::elf::link(args_as_c_strings, output_stream, errors_stream, false, false);
179179
if (result == false) {
180180
std::cout << errors;
181-
}
181+
}
182182
}
183183
}
184184
#elif __APPLE__
@@ -205,7 +205,7 @@ static void link(std::string executable_name, std::string object_file_name, std:
205205
// Execute command
206206
system(build_command.c_str());
207207
}
208-
208+
209209
// Link using lld
210210
else {
211211
// Get macos version, modified from https://stackoverflow.com/a/69176800 with https://creativecommons.org/licenses/by-sa/4.0/ license.
@@ -226,7 +226,7 @@ static void link(std::string executable_name, std::string object_file_name, std:
226226

227227
if (major >= 20) {
228228
major -= 9;
229-
}
229+
}
230230
else {
231231
major -= 4;
232232
}
@@ -246,7 +246,7 @@ static void link(std::string executable_name, std::string object_file_name, std:
246246
perror("popen() failed.");
247247
exit(EXIT_FAILURE);
248248
}
249-
249+
250250
char c;
251251
libclang_rtx_location = "";
252252
while (fread(&c, sizeof c, 1, fpipe)) {
@@ -255,6 +255,30 @@ static void link(std::string executable_name, std::string object_file_name, std:
255255
}
256256
}
257257

258+
// Get macos sdk path
259+
std::string macos_sdk_location = "";
260+
if (std::filesystem::exists("/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk")) {
261+
macos_sdk_location = "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk";
262+
}
263+
else if (std::filesystem::exists("/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk")) {
264+
macos_sdk_location = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk";
265+
}
266+
else {
267+
const char *command = "xcrun --show-sdk-path";
268+
FILE *fpipe = (FILE*)popen(command, "r");
269+
if (!fpipe) {
270+
perror("popen() failed.");
271+
exit(EXIT_FAILURE);
272+
}
273+
274+
char c;
275+
macos_sdk_location = "";
276+
while (fread(&c, sizeof c, 1, fpipe)) {
277+
if (c == '\n') break;
278+
macos_sdk_location += c;
279+
}
280+
}
281+
258282
// Create link args
259283
std::vector<std::string> args = {
260284
"lld",
@@ -268,7 +292,7 @@ static void link(std::string executable_name, std::string object_file_name, std:
268292
std::to_string(major) + ".0.0",
269293
std::to_string(major) + ".0",
270294
"-syslibroot",
271-
"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk",
295+
macos_sdk_location,
272296
"-L/usr/local/lib",
273297
"-lSystem",
274298
libclang_rtx_location
@@ -286,7 +310,7 @@ static void link(std::string executable_name, std::string object_file_name, std:
286310
bool result = lld::macho::link(args_as_c_strings, output_stream, errors_stream, false, false);
287311
if (result == false) {
288312
std::cout << errors;
289-
}
313+
}
290314
}
291315
}
292316
#endif
@@ -306,7 +330,7 @@ static void link(std::string executable_name, std::string object_file_name, std:
306330
"-nologo",
307331
name.c_str()
308332
};
309-
333+
310334
if (link_directives.size() > 0) {
311335
assert(false);
312336
}
@@ -827,7 +851,7 @@ llvm::Value* codegen::Context::get_field_pointer(ast::FieldAccessNode& node) {
827851
type_definition = ast::get_concrete_type((ast::Node*) node.fields_accessed[i], this->type_bindings).as_nominal_type().type_definition;
828852
struct_type = this->get_struct_type(type_definition);
829853
}
830-
854+
831855
// Get pointer to accessed fieldd
832856
size_t last_element = node.fields_accessed.size() - 1;
833857
llvm::Value* ptr = this->builder->CreateStructGEP(struct_type, struct_ptr, type_definition->get_index_of_field(node.fields_accessed[last_element]->value));
@@ -844,7 +868,7 @@ llvm::Value* codegen::Context::get_index_access_pointer(ast::CallNode& node) {
844868
if (((llvm::AllocaInst*) array_ptr)->getAllocatedType()->isPointerTy()) {
845869
array_ptr = this->builder->CreateLoad(array_type->getPointerTo(), array_ptr);
846870
}
847-
871+
848872
return this->builder->CreateGEP(array_type, array_ptr, {llvm::ConstantInt::get(*(this->context), llvm::APInt(64, 0, true)), index}, "", true);
849873
}
850874
else {
@@ -856,7 +880,7 @@ llvm::Value* codegen::Context::get_index_access_pointer(ast::CallNode& node) {
856880
wrapper_ptr
857881
);
858882
}
859-
883+
860884
// Get array pointer
861885
llvm::Value* array_ptr = this->builder->CreateStructGEP(wrapper_type, wrapper_ptr, 1);
862886
array_ptr = this->builder->CreateLoad(array_ptr->getType(), array_ptr);
@@ -888,11 +912,11 @@ llvm::AllocaInst* codegen::Context::copy_expression_to_memory(llvm::Value* point
888912
if (this->has_struct_type(expression)) {
889913
// Store fields
890914
this->store_fields(expression, pointer);
891-
915+
892916
// Return
893917
return nullptr;
894918
}
895-
else if (this->has_array_type(expression)) {
919+
else if (this->has_array_type(expression)) {
896920
// Store array elements
897921
this->store_array_elements(expression, pointer);
898922

@@ -1053,7 +1077,7 @@ void codegen::Context::codegen_types_prototypes(std::vector<ast::TypeNode*> type
10531077
void codegen::Context::codegen_types_bodies(std::vector<ast::TypeNode*> types) {
10541078
for (auto type: types) {
10551079
llvm::StructType* struct_type = this->get_struct_type(type);
1056-
1080+
10571081
std::vector<llvm::Type*> fields;
10581082
for (auto field: type->fields) {
10591083
fields.push_back(as_llvm_type(field->type));
@@ -1070,7 +1094,7 @@ void codegen::Context::codegen_function_prototypes(std::vector<ast::FunctionNode
10701094
if (function->state != ast::FunctionCompletelyTyped) {
10711095
for (auto& specialization: function->specializations) {
10721096
this->type_bindings = specialization.type_bindings;
1073-
1097+
10741098
this->codegen_function_prototypes(
10751099
function->module_path,
10761100
function->identifier->value,
@@ -1109,7 +1133,7 @@ void codegen::Context::codegen_function_prototypes(std::filesystem::path module_
11091133
llvm::Function* f = llvm::Function::Create(function_type, llvm::Function::ExternalLinkage, name, this->module);
11101134

11111135
size_t offset = 0;
1112-
1136+
11131137
if (return_type.is_struct_type() || return_type.is_array()) {
11141138
f->getArg(0)->setName("$result");
11151139
offset += 1;
@@ -1118,7 +1142,7 @@ void codegen::Context::codegen_function_prototypes(std::filesystem::path module_
11181142
// Name arguments
11191143
for (size_t i = 0; i < args.size(); i++) {
11201144
std::string name = args[i]->identifier->value;
1121-
1145+
11221146
if (args_types[i].is_collection() && !args[i]->is_mutable) {
11231147
auto new_args = this->get_collection_as_argument(args_types[i]);
11241148

@@ -1188,7 +1212,7 @@ void codegen::Context::codegen_function_bodies(std::filesystem::path module_path
11881212
this->add_scope();
11891213

11901214
size_t offset = 0;
1191-
1215+
11921216
if (return_type.is_collection()) {
11931217
// Create allocation for argument
11941218
auto allocation = this->create_allocation("$result", f->getArg(0)->getType());
@@ -1227,7 +1251,7 @@ void codegen::Context::codegen_function_bodies(std::filesystem::path module_path
12271251
this->builder->CreateBitCast(
12281252
allocation,
12291253
new_args.struct_type.value()->getPointerTo()
1230-
),
1254+
),
12311255
j
12321256
);
12331257
this->builder->CreateStore(f->getArg(i + offset + j), field_ptr);
@@ -1351,7 +1375,7 @@ llvm::Value* codegen::Context::codegen(ast::AssignmentNode& node) {
13511375
this->delete_binding(pointer, ast::get_concrete_type(node.assignable, this->type_bindings));
13521376
}
13531377
else if (node.assignable->index() == ast::Call) {
1354-
this->delete_binding(pointer, ast::get_concrete_type(node.assignable, this->type_bindings));
1378+
this->delete_binding(pointer, ast::get_concrete_type(node.assignable, this->type_bindings));
13551379
}
13561380
else {
13571381
assert(false);
@@ -1372,7 +1396,7 @@ llvm::Value* codegen::Context::codegen(ast::ReturnNode& node) {
13721396
this->get_binding("$result").pointer
13731397
)
13741398
);
1375-
1399+
13761400
// Return
13771401
this->builder->CreateRetVoid();
13781402
}
@@ -1680,10 +1704,10 @@ llvm::Value* codegen::Context::codegen_size_function(std::variant<llvm::Value*,
16801704
);
16811705
}
16821706
llvm::StructType* array_type = llvm::StructType::getTypeByName(*this->context, "arrayWrapper");
1683-
1707+
16841708
// Get size
16851709
llvm::Value* size_ptr = this->builder->CreateStructGEP(array_type, array_ptr, 0);
1686-
1710+
16871711
// Load size
16881712
return this->builder->CreateLoad(
16891713
this->as_llvm_type(ast::Type("int64")),
@@ -1762,7 +1786,7 @@ llvm::Value* codegen::Context::codegen_call(ast::CallNode& node, std::optional<l
17621786
ast::FunctionNode* function = this->get_function(&node);
17631787

17641788
// Codegen args
1765-
std::vector<llvm::Value*> args;
1789+
std::vector<llvm::Value*> args;
17661790
if (node.identifier->value != "subscript"
17671791
&& node.identifier->value != "size"
17681792
&& node.identifier->value != "print"
@@ -1773,7 +1797,7 @@ llvm::Value* codegen::Context::codegen_call(ast::CallNode& node, std::optional<l
17731797
args.insert(args.begin(), allocation.value());
17741798
}
17751799
}
1776-
1800+
17771801
// Intrinsics
17781802
if (node.args.size() == 2) {
17791803
if (node.identifier->value == "add") {
@@ -1879,7 +1903,7 @@ llvm::Value* codegen::Context::codegen_call(ast::CallNode& node, std::optional<l
18791903

18801904
// Codegen args
18811905
args = this->codegen_args(function, node.args);
1882-
1906+
18831907
// Make call
18841908
return this->builder->CreateCall(llvm_function, args, "calltmp");
18851909
}
@@ -1951,7 +1975,7 @@ llvm::Value* codegen::Context::codegen(ast::IntegerNode& node) {
19511975
else if (ast::get_concrete_type((ast::Node*) &node, this->type_bindings) == ast::Type("int8")) {
19521976
return llvm::ConstantInt::get(*(this->context), llvm::APInt(8, node.value, true));
19531977
}
1954-
1978+
19551979
assert(false);
19561980
return nullptr;
19571981
}
@@ -2012,4 +2036,4 @@ llvm::Value* codegen::Context::codegen(ast::NewNode& node) {
20122036
auto allocation = this->create_heap_allocation(ast::get_concrete_type(node.expression, this->type_bindings));
20132037
this->copy_expression_to_memory(allocation, node.expression);
20142038
return allocation;
2015-
}
2039+
}

0 commit comments

Comments
 (0)