diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7cb0859bb..dbdbad3dd 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v1 - name: (Linux) Download LLVM run: | - sudo apt-get install libllvm11 llvm-11 llvm-11-dev llvm-11-runtime liblld-11-dev liblld-11 + sudo apt-get install zlib1g zlib1g-dev clang-11 libllvm11 llvm-11 llvm-11-dev llvm-11-runtime liblld-11-dev liblld-11 - name: Build run: | mkdir build && cd build diff --git a/CMakeLists.txt b/CMakeLists.txt index 09b746533..67fbb5d43 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,15 +28,10 @@ set(LLVM_LINK_COMPONENTS Analysis BitReader Core - ExecutionEngine InstCombine - Interpreter MC MCDisassembler - MCJIT Object - OrcJIT - RuntimeDyld ScalarOpts Support Target @@ -46,10 +41,11 @@ set(LLVM_LINK_COMPONENTS AsmPrinter Linker LTO - Option WindowsManifest DebugInfoPDB LibDriver + Option + IrReader ) diff --git a/README.md b/README.md index d99093be6..bfaed6969 100644 --- a/README.md +++ b/README.md @@ -127,3 +127,32 @@ C3 on its dedicated Discord: https://discord.gg/qN76R87 - Discuss the language on discord to help iron out syntax. - Stdlib work will soon start, do you want to help out building the C3 std lib? - Do you want to do real compiler work? Everyone is welcome to contribute. + +#### Installing on Ubuntu + +(This installation has been tested on 20.10) + +1. Make sure you have a C compiler that handles C11 and a C++ compiler, such as GCC or Clang. Git also needs to be installed. +2. Install CMake: `sudo apt install cmake` +3. Install LLVM 11: `sudo apt-get install clang-11 zlib1g zlib1g-dev libllvm11 llvm-11 llvm-11-dev llvm-11-runtime liblld-11-dev liblld-11` +4. Clone the C3C github repository: `git clone https://github.com/c3lang/c3c.git` +5. Enter the C3C directory `cd c3c`. +6. Create a build directory `mkdir build` +7. Change directory to the build directory `cd build` +8. Set up CMake build for debug: `cmake -DLLVM_DIR=/usr/lib/llvm-11/cmake -DCMAKE_BUILD_TYPE=Debug ..` +9. Build: `cmake --build .` + +You should now have a `c3c` executable. + +You can try it out by running some sample code: `./c3c compile ../resources/examples/hash.c3` + +#### Installing on OS X using Homebrew + +2. Install CMake: `brew install cmake` +3. Install LLVM 11: `brew install llvm` +4. Clone the C3C github repository: `git clone https://github.com/c3lang/c3c.git` +5. Enter the C3C directory `cd c3c`. +6. Create a build directory `mkdir build` +7. Change directory to the build directory `cd build` +8. Set up CMake build for debug: `cmake ..` +9. Build: `cmake --build .` diff --git a/src/compiler/linker.c b/src/compiler/linker.c index 7e18e0d0f..304c2c0a4 100644 --- a/src/compiler/linker.c +++ b/src/compiler/linker.c @@ -6,58 +6,125 @@ extern bool llvm_link_coff(const char **args, int arg_count, const char** error_ extern bool llvm_link_wasm(const char **args, int arg_count, const char** error_string); extern bool llvm_link_mingw(const char **args, int arg_count, const char** error_string); +static void add_files(const char ***args, const char **files_to_link, unsigned file_count) +{ + for (unsigned i = 0; i < file_count; i++) + { + vec_add(*args, files_to_link[i]); + } +} + static void link_exe(const char *output_file, const char **files_to_link, unsigned file_count) { - int arg_count = (int)file_count + 2; const char **args = NULL; vec_add(args, "-o"); vec_add(args, output_file); - vec_add(args, "-m"); - vec_add(args, platform_target.target_triple); - for (unsigned i = 0; i < file_count; i++) - { - args[i + 2] = files_to_link[i]; - } const char *error = NULL; switch (platform_target.os) { case OS_TYPE_WIN32: break; - case OS_TYPE_WATCHOS: case OS_TYPE_MACOSX: + add_files(&args, files_to_link, file_count); vec_add(args, "-lSystem"); vec_add(args, "-lm"); vec_add(args, "-syslibroot"); vec_add(args, "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk"); - vec_add(args, platform_target.pie ? "-pie" : "-no_pie"); + if (platform_target.pie) + { + vec_add(args, "-macosx_version_min"); + vec_add(args, platform_target.arch == ARCH_TYPE_AARCH64 ? "11.0" : "10.8"); + vec_add(args, "-pie"); + } + else + { + vec_add(args, "-no_pie"); + } + break; + case OS_TYPE_WATCHOS: + case OS_TYPE_IOS: + TODO + case OS_TYPE_WASI: + break; + case OS_TYPE_OPENBSD: + case OS_TYPE_NETBSD: + case OS_TYPE_FREE_BSD: + TODO break; case OS_TYPE_LINUX: + vec_add(args, "-m"); + switch (platform_target.arch) + { + case ARCH_TYPE_X86_64: + vec_add(args, "elf_x86_64"); + if (platform_target.pie || platform_target.pic) + { + vec_add(args, "--eh-frame-hdr"); + vec_add(args, "/usr/lib/x86_64-linux-gnu/crt1.o"); + vec_add(args, "/usr/lib/gcc/x86_64-linux-gnu/10/crtbeginS.o"); + add_files(&args, files_to_link, file_count); + vec_add(args, "/usr/lib/x86_64-linux-gnu/crti.o"); + vec_add(args, "/usr/lib/gcc/x86_64-linux-gnu/10/crtendS.o"); + vec_add(args, "-pie"); + } + else + { + vec_add(args, "/usr/lib/x86_64-linux-gnu/Scrt1.o"); + vec_add(args, "/usr/lib/gcc/x86_64-linux-gnu/10/crtbegin.o"); + add_files(&args, files_to_link, file_count); + vec_add(args, "-lc"); + vec_add(args, "-lm"); + vec_add(args, "/usr/lib/x86_64-linux-gnu/crti.o"); + vec_add(args, "/usr/lib/gcc/x86_64-linux-gnu/10/crtend.o"); + vec_add(args, "-no-pie"); + } + vec_add(args, "/usr/lib/x86_64-linux-gnu/crtn.o"); + vec_add(args, "-L/usr/lib/x86_64-linux-gnu/"); + vec_add(args, "--dynamic-linker=/lib64/ld-linux-x86-64.so.2"); + break; + case ARCH_TYPE_X86: + TODO + vec_add(args, "elf_i386"); + break; + case ARCH_TYPE_AARCH64: + TODO + vec_add(args, "aarch64elf"); + break; + case ARCH_TYPE_RISCV32: + TODO + vec_add(args, "elf32lriscv"); + break; + case ARCH_TYPE_RISCV64: + vec_add(args, "elf64lriscv"); + TODO + break; + default: + UNREACHABLE + } vec_add(args, "-L/usr/lib/"); vec_add(args, "-L/lib/"); - vec_add(args, "-lc"); - vec_add(args, "-lm"); - vec_add(args, platform_target.pie ? "-pie" : "-no-pie"); break; default: + add_files(&args, files_to_link, file_count); + vec_add(args, platform_target.pie ? "-pie" : "-no_pie"); break; } - vec_add(args, platform_target.pie ? "-pie" : "-no_pie"); bool success; switch (platform_target.object_format) { case OBJ_FORMAT_COFF: - success = llvm_link_coff(args, arg_count, &error); + success = llvm_link_coff(args, (int)vec_size(args), &error); break; case OBJ_FORMAT_ELF: - success = llvm_link_elf(args, arg_count, &error); + success = llvm_link_elf(args, (int)vec_size(args), &error); break; case OBJ_FORMAT_MACHO: - success = llvm_link_macho(args, arg_count, &error); + success = llvm_link_macho(args, (int)vec_size(args), &error); break; case OBJ_FORMAT_WASM: - success = llvm_link_wasm(args, arg_count, &error); + success = llvm_link_wasm(args, (int)vec_size(args), &error); break; default: UNREACHABLE @@ -90,3 +157,26 @@ void linker(const char *output_file, const char **files, unsigned file_count) { link_exe(output_file, files, file_count); } + +/** + * From Clang + * .Cases("aarch64elf", "aarch64linux", {ELF64LEKind, EM_AARCH64}) + .Cases("aarch64elfb", "aarch64linuxb", {ELF64BEKind, EM_AARCH64}) + .Cases("armelf", "armelf_linux_eabi", {ELF32LEKind, EM_ARM}) + .Case("elf32_x86_64", {ELF32LEKind, EM_X86_64}) + .Cases("elf32btsmip", "elf32btsmipn32", {ELF32BEKind, EM_MIPS}) + .Cases("elf32ltsmip", "elf32ltsmipn32", {ELF32LEKind, EM_MIPS}) + .Case("elf32lriscv", {ELF32LEKind, EM_RISCV}) + .Cases("elf32ppc", "elf32ppclinux", {ELF32BEKind, EM_PPC}) + .Cases("elf32lppc", "elf32lppclinux", {ELF32LEKind, EM_PPC}) + .Case("elf64btsmip", {ELF64BEKind, EM_MIPS}) + .Case("elf64ltsmip", {ELF64LEKind, EM_MIPS}) + .Case("elf64lriscv", {ELF64LEKind, EM_RISCV}) + .Case("elf64ppc", {ELF64BEKind, EM_PPC64}) + .Case("elf64lppc", {ELF64LEKind, EM_PPC64}) + .Cases("elf_amd64", "elf_x86_64", {ELF64LEKind, EM_X86_64}) + .Case("elf_i386", {ELF32LEKind, EM_386}) + .Case("elf_iamcu", {ELF32LEKind, EM_IAMCU}) + .Case("elf64_sparc", {ELF64BEKind, EM_SPARCV9}) + .Case("msp430elf", {ELF32LEKind, EM_MSP430}) + */