From ccffa03de29a531dbfbad69b977e8f96a6433733 Mon Sep 17 00:00:00 2001 From: DylanDoesProgramming <120761889+DylanDoesProgramming664@users.noreply.github.com> Date: Tue, 2 Dec 2025 18:42:36 -0500 Subject: [PATCH] musl-based linux distro support (#2577) * added switch statement to link musl-based linux distros to ld-musl-x86-64.so.2 * Update linker.c /lib/ld-musl-x86-64.so.1 is musl's ld so. My bad * don't need ENV_MUSLEABI.* in the switch for x86_64 * typo * Added a CI test for an Alpine Linux container * Update main.yml Forgot to have bundle_output job use `env.LLVM_RELEASE_VERSION_ALPINEv3_22`. * Added env.LLVM_RELEASE_VERSION_ALPINEv3_22 to `upload artifacts` * changed bundle name to c3-musl-${{matrix,build_type}}.tar.gz * Undid an accidental name change in build-linux-ubuntu22 * Update main.yml sudo doesn't exist in alpine by default, and runs in root by default. * Update main.yml * Update main.yml * Update main.yml * Update main.yml `--linker=builtin` fails because it forces search of `/lib64/ld-linux-x86-64.so.2`. lib64 doesn't exist on musl unless created as a symlink, and the appropriate so is /lib/ld-musl-.so.1 * Update main.yml * Update main.yml * Update main.yml * Update main.yml make isn't in alpine by default. added it in for risc-v example. * gcc-riscv-none-elf is alpine's package * using realpath for c3c over using relative pathing * Have to use relative path for arguments in compiler test * added --linker=builtin to * Added linux-musl- targets * Added more ld targets for glibc * set both testproject libs as folders until they behave better * added linux-musl-x64 target to clib2 * added riscv targets for ld-linux * ubuntu doesn't have ld in /lib, but solely in /lib64? * Make MUSL distinct from the target. * Fix default in project schema * Fix define * Fix manifests. * Update main.yml add --linux-libc flag for builtin linking * Grammar refresh * Update releasenotes. --------- Co-authored-by: Christoffer Lerno --- .github/workflows/main.yml | 182 +++ .gitignore | 5 + releasenotes.md | 1 + .../examples/embedded/riscv-qemu/Makefile | 6 +- resources/grammar/grammar_proposal.y | 1337 ----------------- resources/project_schema.json | 9 + .../testproject/lib/clib.c3l/manifest.json | 24 +- resources/testproject/lib/clib2.c3l | Bin 1168 -> 0 bytes .../lib/clib2.c3l/__MACOSX/._manifest.json | Bin 0 -> 264 bytes resources/testproject/lib/clib2.c3l/clib2.c3i | 3 + resources/testproject/lib/clib2.c3l/hello.c | 5 + .../testproject/lib/clib2.c3l/manifest.json | 14 + src/build/build.h | 10 + src/build/build_internal.h | 5 + src/build/build_options.c | 7 + src/build/builder.c | 42 +- src/build/project.c | 6 + src/compiler/linker.c | 54 +- src/compiler/target.c | 67 +- src/utils/hostinfo.c | 2 +- 20 files changed, 397 insertions(+), 1382 deletions(-) delete mode 100644 resources/grammar/grammar_proposal.y delete mode 100644 resources/testproject/lib/clib2.c3l create mode 100644 resources/testproject/lib/clib2.c3l/__MACOSX/._manifest.json create mode 100644 resources/testproject/lib/clib2.c3l/clib2.c3i create mode 100644 resources/testproject/lib/clib2.c3l/hello.c create mode 100644 resources/testproject/lib/clib2.c3l/manifest.json diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4df84148b..0a91526ba 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,6 +12,7 @@ env: LLVM_RELEASE_VERSION_LINUX: 19 LLVM_RELEASE_VERSION_OPENBSD: 19 LLVM_RELEASE_VERSION_UBUNTU22: 19 + LLVM_RELEASE_VERSION_ALPINEv3_22: 20 LLVM_DEV_VERSION: 22 jobs: @@ -409,6 +410,187 @@ jobs: name: c3-linux-${{matrix.build_type}} path: c3-linux-${{matrix.build_type}}.tar.gz + build-linux-alpine: + runs-on: ubuntu-22.04 + container: + image: alpine:3.22 + strategy: + # Don't abort runners if a single one fails + fail-fast: false + matrix: + build_type: [Release, Debug] + llvm_version: [18, 19, 20] + + steps: + - uses: actions/checkout@v4 + - name: Install common deps + run: | + apk update + apk add zlib-dev zlib-static python3 samurai cmake curl-dev curl-static openssl-dev + + - name: Install Clang ${{matrix.llvm_version}} + run: | + apk add "llvm${{matrix.llvm_version}}-dev" "llvm${{matrix.llvm_version}}-static" \ + "llvm${{matrix.llvm_version}}-gtest" "llvm${{matrix.llvm_version}}-linker-tools" \ + "llvm${{matrix.llvm_version}}-test-utils" "llvm${{matrix.llvm_version}}-test-utils-pyc" \ + "lld${{matrix.llvm_version}}-dev" "clang${{matrix.llvm_version}}-dev" \ + "clang${{matrix.llvm_version}}-extra-tools" "clang${{matrix.llvm_version}}-static" + - name: CMake + if: matrix.llvm_version == env.LLVM_DEV_VERSION + run: | + cmake -B build \ + -G Ninja \ + -DCMAKE_BUILD_TYPE=${{matrix.build_type}}" \ + -DCMAKE_C_COMPILER=clang-${{matrix.llvm_version}} \ + -DCMAKE_CXX_COMPILER=clang++-${{matrix.llvm_version}} \ + -DCMAKE_LINKER=lld-link-${{matrix.llvm_version}} \ + -DCMAKE_OBJCOPY=llvm-objcopy-${{matrix.llvm_version}} \ + -DCMAKE_STRIP=llvm-strip-${{matrix.llvm_version}} \ + -DCMAKE_DLLTOOL=llvm-dlltool-${{matrix.llvm_version}} \ + -DLLVM_ENABLE_LIBXML2=OFF \ + -DC3_LINK_DYNAMIC=ON \ + -DC3_LLVM_VERSION=${{matrix.llvm_version}} + cmake --build build + - name: CMake_Stable + if: matrix.llvm_version >= 18 && matrix.llvm_version != env.LLVM_DEV_VERSION + run: | + cmake -B build \ + -G Ninja \ + -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \ + -DCMAKE_C_COMPILER=clang-${{matrix.llvm_version}} \ + -DCMAKE_CXX_COMPILER=clang++-${{matrix.llvm_version}} \ + -DCMAKE_LINKER=lld-link-${{matrix.llvm_version}} \ + -DCMAKE_OBJCOPY=llvm-objcopy-${{matrix.llvm_version}} \ + -DCMAKE_STRIP=llvm-strip-${{matrix.llvm_version}} \ + -DCMAKE_DLLTOOL=llvm-dlltool-${{matrix.llvm_version}} \ + -DLLVM_ENABLE_LIBXML2=OFF \ + -DC3_LINK_DYNAMIC=ON \ + -DC3_LLVM_VERSION=${{matrix.llvm_version}}.1 + cmake --build build + + - name: Compile and run some examples + run: | + export C3C="$(realpath ./build/c3c)" + cd resources + "$C3C" compile examples/base64.c3 + "$C3C" compile examples/binarydigits.c3 + "$C3C" compile examples/brainfk.c3 + "$C3C" compile examples/factorial_macro.c3 + "$C3C" compile examples/fasta.c3 + "$C3C" compile examples/gameoflife.c3 + "$C3C" compile examples/hash.c3 + "$C3C" compile-only examples/levenshtein.c3 + "$C3C" compile examples/load_world.c3 + "$C3C" compile-only examples/map.c3 + "$C3C" compile examples/mandelbrot.c3 + "$C3C" compile examples/plus_minus.c3 + "$C3C" compile examples/nbodies.c3 + "$C3C" compile examples/spectralnorm.c3 + "$C3C" compile examples/swap.c3 + "$C3C" compile examples/contextfree/boolerr.c3 + "$C3C" compile examples/contextfree/dynscope.c3 + "$C3C" compile examples/contextfree/guess_number.c3 + "$C3C" compile examples/contextfree/multi.c3 + "$C3C" compile examples/contextfree/cleanup.c3 + "$C3C" compile-run examples/hello_world_many.c3 + "$C3C" compile-run examples/time.c3 + "$C3C" compile-run examples/fannkuch-redux.c3 + "$C3C" compile-run examples/contextfree/boolerr.c3 + "$C3C" compile-run examples/load_world.c3 + "$C3C" compile-run examples/process.c3 + "$C3C" compile-run examples/ls.c3 + # "$C3C" compile-run --linker=builtin linux_stack.c3 # Program will hang due to incorrect linking to `/lib64/ld-linux-x86-64.so.2` instead of `/lib/ld-musl-x86_64.so.1` + "$C3C" compile-run linux_stack.c3 + "$C3C" compile-run examples/args.c3 -- foo -bar "baz baz" + + - name: Compile and run dynlib-test + run: | + export C3C="$(realpath ./build/c3c)" + cd resources/examples/dynlib-test + "$C3C" -vv dynamic-lib add.c3 + mv add.so libadd.so + cc test.c -L. -ladd -Wl,-rpath=. + ./a.out + "$C3C" compile-run test.c3 -L . -l add -z -Wl,-rpath=. + + - name: Compile and run staticlib-test + run: | + export C3C="$(realpath ./build/c3c)" + cd resources/examples/staticlib-test + "$C3C" -vv static-lib add.c3 + mv add.a libadd.a + cc test.c -L. -ladd + ./a.out + "$C3C" compile-run test.c3 -L . -l add + + - name: Compile run unit tests + run: | + export C3C="$(realpath ./build/c3c)" + cd test + "$C3C" compile-test unit -D SLOW_TESTS + + - name: Build testproject + run: | + export C3C="$(realpath ./build/c3c)" + cd resources/testproject + "$C3C" run -vvv --trust=full + + - name: Test WASM + run: | + export C3C="$(realpath ./build/c3c)" + cd resources/testfragments + "$C3C" compile --target wasm32 -g0 --no-entry -Os wasm4.c3 + + - name: Install QEMU and Risc-V toolchain + run: | + apk add qemu-dev qemu-system-riscv32 gcc-riscv-none-elf make + + - name: Compile and run Baremetal Risc-V Example + run: | + cd resources/examples/embedded/riscv-qemu + make C3C_PATH=../../../../build/ run + + - name: Build testproject direct linker + run: | + export C3C="$(realpath ./build/c3c)" + cd resources/testproject + "$C3C" run -vvv --linker=builtin --trust=full --linux-libc=musl + + - name: Init a library & a project + run: | + ./build/c3c init-lib mylib + ls mylib.c3l + ./build/c3c init myproject + ls myproject + + - name: Vendor-fetch + run: | + "$(realpath ./build/c3c)" vendor-fetch raylib55 + + - name: run compiler tests + run: | + export C3C="$(realpath ./build/c3c)" + cd test + "$C3C" compile-run -O1 src/test_suite_runner.c3 -- ../build/c3c test_suite/ + + - name: bundle_output + if: matrix.llvm_version == env.LLVM_RELEASE_VERSION_ALPINEv3_22 + run: | + mkdir c3 + cp -r lib c3 + cp msvc_build_libraries.py c3 + cp build/c3c c3 + cp README.md c3 + cp releasenotes.md c3 + tar -czf c3-musl-${{matrix.build_type}}.tar.gz c3 + + - name: upload artifacts + if: matrix.llvm_version == env.LLVM_RELEASE_VERSION_ALPINEv3_22 + uses: actions/upload-artifact@v4 + with: + name: c3-musl-${{matrix.build_type}} + path: c3-musl-${{matrix.build_type}}.tar.gz + build-linux-ubuntu22: runs-on: ubuntu-22.04 strategy: diff --git a/.gitignore b/.gitignore index 3d5623f87..5d1cfc719 100644 --- a/.gitignore +++ b/.gitignore @@ -92,3 +92,8 @@ result /test/tmp/* /test/testrun /test/test_suite_runner + +# patches, originals and rejects +*.patch +*.rej +*.orig diff --git a/releasenotes.md b/releasenotes.md index d121a6eac..f9f0915cb 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -18,6 +18,7 @@ - Xtensa target no longer enabled by default on LLVM 22, Compile with `-DXTENSA_ENABLE` to enable it instead - Add `float[<3>] x = { .xy = 1.2, .z = 3.3 }` swizzle initialization for vectors. #2599 - Support `int $foo...` arguments. #2601 +- Add musl support with `--linux-libc=musl`. ### Fixes - `Foo.is_eq` would return false if the type was a `typedef` and had an overload, but the underlying type was not comparable. diff --git a/resources/examples/embedded/riscv-qemu/Makefile b/resources/examples/embedded/riscv-qemu/Makefile index c70ab89a7..cd2951af6 100644 --- a/resources/examples/embedded/riscv-qemu/Makefile +++ b/resources/examples/embedded/riscv-qemu/Makefile @@ -6,10 +6,12 @@ hello.a: $(SRCS_C3) $(C3C_PATH)c3c -g --use-stdlib=no --no-entry --target elf-riscv32 static-lib $(SRCS_C3) start.o: start.s - riscv64-unknown-elf-as -g -march=rv32i -mabi=ilp32 -misa-spec=20191213 -o start.o start.s + riscv64-unknown-elf-as -g -march=rv32i -mabi=ilp32 -misa-spec=20191213 -o start.o start.s \ + || riscv-none-elf-as -g -march=rv32i -mabi=ilp32 -misa-spec=20191213 -o start.o start.s hello.elf: hello.a start.o baremetal.ld - riscv64-unknown-elf-ld -T baremetal.ld -m elf32lriscv -o hello.elf hello.a start.o + riscv64-unknown-elf-ld -T baremetal.ld -m elf32lriscv -o hello.elf hello.a start.o \ + || riscv-none-elf-ld -T baremetal.ld -m elf32lriscv -o hello.elf hello.a start.o run: hello.elf qemu-system-riscv32 -nographic -serial mon:stdio -machine virt -semihosting -bios hello.elf diff --git a/resources/grammar/grammar_proposal.y b/resources/grammar/grammar_proposal.y deleted file mode 100644 index 25b694f36..000000000 --- a/resources/grammar/grammar_proposal.y +++ /dev/null @@ -1,1337 +0,0 @@ -%{ - -#include -#include "grammar.tab.h" -#include "lex.yy.h" -#define YYERROR_VERBOSE -void yyerror(YYLTYPE * yylloc_param , yyscan_t yyscanner, const char *yymsgp); -%} -%locations -%pure-parser -%lex-param {void *scanner} -%parse-param {void *scanner} - -%token IDENT HASH_IDENT CT_IDENT CONST_IDENT -%token TYPE_IDENT CT_TYPE_IDENT -%token AT_TYPE_IDENT AT_IDENT CT_INCLUDE -%token STRING_LITERAL INTEGER -%token CT_AND_OP CT_OR_OP CT_CONCAT_OP CT_EXEC -%token INC_OP DEC_OP SHL_OP SHR_OP LE_OP GE_OP EQ_OP NE_OP -%token AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN -%token LGENPAR RGENPAR -%token SUB_ASSIGN SHL_ASSIGN SHR_ASSIGN AND_ASSIGN -%token XOR_ASSIGN OR_ASSIGN VAR NUL ELVIS NEXTCASE ANYFAULT -%token MODULE IMPORT DEF EXTERN -%token CHAR SHORT INT LONG FLOAT DOUBLE CONST VOID USZ ISZ UPTR IPTR ANY -%token ICHAR USHORT UINT ULONG BOOL INT128 UINT128 FLOAT16 FLOAT128 BFLOAT16 -%token TYPEID BITSTRUCT STATIC BANGBANG AT_CONST_IDENT HASH_TYPE_IDENT -%token STRUCT UNION ENUM ELLIPSIS DOTDOT BYTES - -%token CT_ERROR -%token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR CONTINUE BREAK RETURN FOREACH_R FOREACH INTERFACE -%token FN FAULT MACRO CT_IF CT_ENDIF CT_ELSE CT_SWITCH CT_CASE CT_DEFAULT CT_FOR CT_FOREACH CT_ENDFOREACH -%token CT_ENDFOR CT_ENDSWITCH BUILTIN IMPLIES CT_ECHO CT_ASSERT CT_EVALTYPE CT_VATYPE -%token TRY CATCH SCOPE DEFER LVEC RVEC OPTELSE CT_TYPEFROM CT_TYPEOF TLOCAL -%token CT_VASPLAT INLINE DISTINCT CT_VACONST CT_NAMEOF CT_VAREF CT_VACOUNT CT_VAARG -%token CT_SIZEOF CT_STRINGIFY CT_QNAMEOF CT_OFFSETOF CT_VAEXPR CT_FEATURE -%token CT_EXTNAMEOF CT_EVAL CT_DEFINED CT_ALIGNOF ASSERT -%token ASM CHAR_LITERAL REAL TRUE FALSE CT_CONST_IDENT -%token LBRAPIPE RBRAPIPE HASH_CONST_IDENT CT_ASSIGNABLE CT_AND CT_IS_CONST - -%start translation_unit -%% - -path - : IDENT SCOPE - | path IDENT SCOPE - ; - -path_const - : path CONST_IDENT - | CONST_IDENT - ; - -path_ident - : path IDENT - | IDENT - ; - -path_at_ident - : path AT_IDENT - | AT_IDENT - ; - -ident_expr - : CONST_IDENT - | IDENT - | AT_IDENT - ; - -local_ident_expr - : CT_IDENT - | HASH_IDENT - ; - -ct_call - : CT_ALIGNOF - | CT_EXTNAMEOF - | CT_NAMEOF - | CT_OFFSETOF - | CT_QNAMEOF - ; - -ct_castable - : CT_ASSIGNABLE - ; - -ct_analyse - : CT_EVAL - | CT_SIZEOF - | CT_STRINGIFY - | CT_IS_CONST - ; - -ct_vaarg - : CT_VACONST - | CT_VAARG - | CT_VAREF - | CT_VAEXPR - ; - -flat_path - : primary_expr param_path - | type - | primary_expr - ; - -maybe_optional_type - : optional_type - | empty - ; - -string_expr - : STRING_LITERAL - | string_expr STRING_LITERAL - ; - -bytes_expr - : BYTES - | bytes_expr BYTES - ; - -expr_block - : LBRAPIPE opt_stmt_list RBRAPIPE - ; - -base_expr - : string_expr - | INTEGER - | bytes_expr - | NUL - | CHAR_LITERAL - | REAL - | TRUE - | FALSE - | base_expr_assignable - ; - -base_expr_assignable - : BUILTIN CONST_IDENT - | BUILTIN IDENT - | path ident_expr opt_generic_parameters - | ident_expr opt_generic_parameters - | local_ident_expr - | type '.' access_ident - | type '.' CONST_IDENT - | '(' expr ')' - | expr_block - | ct_call '(' flat_path ')' - | ct_vaarg '[' expr ']' - | ct_analyse '(' expression_list ')' - | CT_DEFINED '(' arg_list ')' - | CT_VACOUNT - | CT_FEATURE '(' CONST_IDENT ')' - | ct_castable '(' expr ',' type ')' - | lambda_decl compound_statement - ; - -primary_expr - : base_expr - | initializer_list - ; - -range_loc - : expr - | '^' expr - ; - -range_expr - : range_loc DOTDOT range_loc - | range_loc DOTDOT - | DOTDOT range_loc - | range_loc ':' range_loc - | ':' range_loc - | range_loc ':' - | DOTDOT - ; - -call_inline_attributes - : AT_IDENT - | call_inline_attributes AT_IDENT - ; - -call_invocation - : '(' call_arg_list ')' - | '(' call_arg_list ')' call_inline_attributes - ; - -access_ident - : IDENT - | AT_IDENT - | HASH_IDENT - | CT_EVAL '(' expr ')' - | TYPEID - ; - -call_trailing - : '[' range_loc ']' - | '[' range_expr ']' - | call_invocation - | call_invocation compound_statement - | '.' access_ident - | INC_OP - | DEC_OP - | '!' - | BANGBANG - ; - -call_stmt_expr - : base_expr_assignable - | call_stmt_expr call_trailing - ; - -call_expr - : primary_expr - | call_expr call_trailing - ; - -unary_expr - : call_expr - | unary_op unary_expr - ; - -unary_stmt_expr - : call_stmt_expr - | unary_op unary_expr - ; - -unary_op - : '&' - | AND_OP - | '*' - | '+' - | '-' - | '~' - | '!' - | INC_OP - | DEC_OP - | '(' type ')' - ; - -mult_op - : '*' - | '/' - | '%' - ; - -mult_expr - : unary_expr - | mult_expr mult_op unary_expr - ; - -mult_stmt_expr - : unary_stmt_expr - | mult_stmt_expr mult_op unary_expr - ; - -shift_op - : SHL_OP - | SHR_OP - ; - -shift_expr - : mult_expr - | shift_expr shift_op mult_expr - ; - -shift_stmt_expr - : mult_stmt_expr - | shift_stmt_expr shift_op mult_expr - ; - -bit_op - : '&' - | '^' - | '|' - ; - -bit_expr - : shift_expr - | bit_expr bit_op shift_expr - ; - -bit_stmt_expr - : shift_stmt_expr - | bit_stmt_expr bit_op shift_expr - ; - -additive_op - : '+' - | '-' - | CT_CONCAT_OP - ; - -additive_expr - : bit_expr - | additive_expr additive_op bit_expr - ; - -additive_stmt_expr - : bit_stmt_expr - | additive_stmt_expr additive_op bit_expr - ; - -relational_op - : '<' - | '>' - | LE_OP - | GE_OP - | EQ_OP - | NE_OP - ; - -relational_expr - : additive_expr - | relational_expr relational_op additive_expr - ; - -relational_stmt_expr - : additive_stmt_expr - | relational_stmt_expr relational_op additive_expr - ; - -try_catch_rhs_expr - : call_expr - | lambda_decl IMPLIES relational_expr - ; - -try_chain_expr - : relational_expr - | lambda_decl IMPLIES relational_expr - ; - -and_expr - : relational_expr - | and_expr AND_OP relational_expr - | and_expr CT_AND_OP relational_expr - ; - -and_stmt_expr - : relational_stmt_expr - | and_stmt_expr AND_OP relational_expr - | and_stmt_expr CT_AND_OP relational_expr - ; - -or_expr - : and_expr - | or_expr OR_OP and_expr - | or_expr CT_OR_OP and_expr - ; - -or_stmt_expr - : and_stmt_expr - | or_stmt_expr OR_OP and_expr - | or_stmt_expr CT_OR_OP and_expr - ; - -suffix_expr - : or_expr - | or_expr '?' - | or_expr '?' '!' - ; - -suffix_stmt_expr - : or_stmt_expr - | or_stmt_expr '?' - | or_stmt_expr '?' '!' - ; - -ternary_expr - : suffix_expr - | or_expr '?' expr ':' ternary_expr - | suffix_expr ELVIS ternary_expr - | suffix_expr OPTELSE ternary_expr - | lambda_decl implies_body - ; - -ternary_stmt_expr - : suffix_stmt_expr - | or_stmt_expr '?' expr ':' ternary_expr - | suffix_stmt_expr ELVIS ternary_expr - | suffix_stmt_expr OPTELSE ternary_expr - | lambda_decl implies_body - ; - -assignment_op - : '=' - | ADD_ASSIGN - | SUB_ASSIGN - | MUL_ASSIGN - | DIV_ASSIGN - | MOD_ASSIGN - | SHL_ASSIGN - | SHR_ASSIGN - | AND_ASSIGN - | XOR_ASSIGN - | OR_ASSIGN - ; - -empty - : /*empty*/ - ; - -assignment_expr - : ternary_expr - | CT_TYPE_IDENT '=' type - | unary_expr assignment_op assignment_expr - ; - -assignment_stmt_expr - : ternary_stmt_expr - | CT_TYPE_IDENT '=' type - | unary_stmt_expr assignment_op assignment_expr - ; - -implies_body - : IMPLIES expr - ; - -lambda_decl - : FN maybe_optional_type fn_parameter_list opt_attributes - ; - -expr_no_list - : assignment_stmt_expr - ; - -expr - : assignment_expr - ; - -constant_expr - : ternary_expr - ; - -param_path_element - : '[' expr ']' - | '[' expr DOTDOT expr ']' - | '.' primary_expr - ; - -param_path - : param_path_element - | param_path param_path_element - ; - -arg_name - : IDENT - | CT_TYPE_IDENT - | HASH_IDENT - | CT_IDENT - ; -arg - : param_path '=' expr - | param_path '=' type - | param_path - | arg_name ':' expr - | arg_name ':' type - | type - | expr - | CT_VASPLAT - | CT_VASPLAT '[' range_expr ']' - | ELLIPSIS expr - ; - -arg_list - : arg - | arg_list ',' arg - | arg_list ',' - ; - -opt_arg_list - : arg_list - | empty - ; - -call_arg_list - : opt_arg_list - | opt_arg_list ';' - | opt_arg_list ';' parameters - ; - -interfaces - : TYPE_IDENT opt_generic_parameters - | interfaces ',' TYPE_IDENT opt_generic_parameters - ; - -opt_interface_impl - : '(' interfaces ')' - | '(' ')' - | empty - ; - -enum_constants - : enum_constant - | enum_constants ',' enum_constant - ; - -enum_list - : enum_constants - | enum_constants ',' - ; - -enum_constant - : CONST_IDENT opt_attributes - | CONST_IDENT opt_attributes '=' constant_expr - ; - -identifier_list - : IDENT - | identifier_list ',' IDENT - ; - -enum_param_decl - : type IDENT - | INLINE type IDENT - ; - -builtin_type - : VOID - | BOOL - | CHAR - | ICHAR - | SHORT - | USHORT - | INT - | UINT - | LONG - | ULONG - | INT128 - | UINT128 - | FLOAT - | DOUBLE - | FLOAT16 - | BFLOAT16 - | FLOAT128 - | IPTR - | UPTR - | ISZ - | USZ - | ANYFAULT - | ANY - | TYPEID - ; - -base_type - : builtin_type - | TYPE_IDENT opt_generic_parameters - | path TYPE_IDENT opt_generic_parameters - | CT_TYPE_IDENT - | CT_TYPEOF '(' expr ')' - | CT_TYPEFROM '(' constant_expr ')' - | CT_VATYPE '[' constant_expr ']' - | CT_EVALTYPE '(' constant_expr ')' - ; - -base_type_non_generic - : builtin_type - | TYPE_IDENT - | path TYPE_IDENT - | CT_TYPE_IDENT - | CT_TYPEOF '(' expr ')' - | CT_TYPEFROM '(' constant_expr ')' - | CT_VATYPE '[' constant_expr ']' - | CT_EVALTYPE '(' constant_expr ')' - ; - -type_non_generic - : base_type_non_generic - | type_non_generic type_suffix - ; - -type_suffix - : '*' - | '[' constant_expr ']' - | '[' ']' - | '[' '*' ']' - | '[' '?' ']' - | LVEC constant_expr RVEC - | LVEC '*' RVEC - | LVEC '?' RVEC - ; -type - : base_type - | type type_suffix - ; - -optional_type - : type - | type '!' - ; - -local_decl_after_type - : CT_IDENT - | CT_IDENT '=' constant_expr - | IDENT opt_attributes - | IDENT opt_attributes '=' expr - ; - -local_decl_storage - : STATIC - | TLOCAL - ; - -decl_or_expr - : var_decl - | optional_type local_decl_after_type - | expr - ; - -var_decl - : VAR IDENT '=' expr - | VAR CT_IDENT '=' expr - | VAR CT_IDENT - | VAR CT_TYPE_IDENT '=' type - | VAR CT_TYPE_IDENT - ; - -initializer_list - : '{' opt_arg_list '}' - ; - -ct_case_stmt - : CT_CASE constant_expr ':' opt_stmt_list - | CT_CASE type ':' opt_stmt_list - | CT_DEFAULT ':' opt_stmt_list - ; - -ct_switch_body - : ct_case_stmt - | ct_switch_body ct_case_stmt - ; - -ct_for_stmt - : CT_FOR '(' for_cond ')' opt_stmt_list CT_ENDFOR - ; - -ct_foreach_stmt - : CT_FOREACH '(' CT_IDENT ':' expr ')' opt_stmt_list CT_ENDFOREACH - | CT_FOREACH '(' CT_IDENT ',' CT_IDENT ':' expr ')' opt_stmt_list CT_ENDFOREACH - ; -ct_switch - : CT_SWITCH '(' constant_expr ')' - | CT_SWITCH '(' type ')' - | CT_SWITCH - ; - -ct_switch_stmt - : ct_switch ct_switch_body CT_ENDSWITCH - ; - -var_stmt - : var_decl ';' - ; - -decl_stmt_after_type - : local_decl_after_type - | decl_stmt_after_type ',' local_decl_after_type - ; - -declaration_stmt - : const_declaration - | local_decl_storage optional_type decl_stmt_after_type ';' - | optional_type decl_stmt_after_type ';' - ; - -return_stmt - : RETURN expr ';' - | RETURN ';' - ; - -catch_unwrap_list - : relational_expr - | catch_unwrap_list ',' relational_expr - ; - -catch_unwrap - : CATCH catch_unwrap_list - | CATCH IDENT '=' catch_unwrap_list - | CATCH type IDENT '=' catch_unwrap_list - ; - -try_unwrap - : TRY try_catch_rhs_expr - | TRY IDENT '=' try_chain_expr - | TRY type IDENT '=' try_chain_expr - ; - -try_unwrap_chain - : try_unwrap - | try_unwrap_chain AND_OP try_unwrap - | try_unwrap_chain AND_OP try_chain_expr - ; - -default_stmt - : DEFAULT ':' opt_stmt_list - ; - -case_stmt - : CASE expr ':' opt_stmt_list - | CASE expr DOTDOT expr ':' opt_stmt_list - | CASE type ':' opt_stmt_list - ; - -switch_body - : case_stmt - | default_stmt - | switch_body case_stmt - | switch_body default_stmt - ; - -cond_repeat - : decl_or_expr - | cond_repeat ',' decl_or_expr - ; - -cond - : try_unwrap_chain - | catch_unwrap - | cond_repeat - | cond_repeat ',' try_unwrap_chain - | cond_repeat ',' catch_unwrap - ; - -else_part - : ELSE if_stmt - | ELSE compound_statement - ; - -if_stmt - : IF optional_label paren_cond '{' switch_body '}' - | IF optional_label paren_cond '{' switch_body '}' else_part - | IF optional_label paren_cond statement - | IF optional_label paren_cond compound_statement else_part - ; - -expr_list_eos - : expression_list ';' - | ';' - ; - -cond_eos - : cond ';' - | ';' - ; - -for_cond - : expr_list_eos cond_eos expression_list - | expr_list_eos cond_eos - ; - -for_stmt - : FOR optional_label '(' for_cond ')' statement - ; - -paren_cond - : '(' cond ')' - ; - -while_stmt - : WHILE optional_label paren_cond statement - ; - -do_stmt - : DO optional_label compound_statement WHILE '(' expr ')' ';' - | DO optional_label compound_statement ';' - ; - -optional_label_target - : CONST_IDENT - | empty - ; - -continue_stmt - : CONTINUE optional_label_target ';' - ; - -break_stmt - : BREAK optional_label_target ';' - ; - -nextcase_stmt - : NEXTCASE CONST_IDENT ':' expr ';' - | NEXTCASE expr ';' - | NEXTCASE CONST_IDENT ':' type ';' - | NEXTCASE type ';' - | NEXTCASE CONST_IDENT ':' DEFAULT ';' - | NEXTCASE DEFAULT ';' - | NEXTCASE ';' - ; - -foreach_var - : optional_type '&' IDENT - | optional_type IDENT - | '&' IDENT - | IDENT - ; - -foreach_vars - : foreach_var - | foreach_var ',' foreach_var - ; - -foreach_stmt - : FOREACH optional_label '(' foreach_vars ':' expr ')' statement - | FOREACH_R optional_label '(' foreach_vars ':' expr ')' statement - ; - -defer_stmt - : DEFER statement - | DEFER TRY statement - | DEFER CATCH statement - | DEFER '(' CATCH IDENT ')' statement - ; - -ct_if_stmt - : CT_IF constant_expr ':' opt_stmt_list CT_ENDIF - | CT_IF constant_expr ':' opt_stmt_list CT_ELSE opt_stmt_list CT_ENDIF - ; - -assert_expr_list - : expr - | expr ',' assert_expr_list - ; - -assert_stmt - : ASSERT '(' expr ')' ';' - | ASSERT '(' expr ',' assert_expr_list ')' ';' - ; - -asm_stmts - : asm_stmt - | asm_stmts asm_stmt - ; - -asm_instr - : INT - | IDENT - | INT '.' IDENT - | IDENT '.' IDENT - ; - -asm_addr - : asm_expr - | asm_expr additive_op asm_expr - | asm_expr additive_op asm_expr '*' INTEGER - | asm_expr additive_op asm_expr '*' INTEGER additive_op INTEGER - | asm_expr additive_op asm_expr shift_op INTEGER - | asm_expr additive_op asm_expr additive_op INTEGER - ; - -asm_expr - : CT_IDENT - | CT_CONST_IDENT - | IDENT - | '&' IDENT - | CONST_IDENT - | REAL - | INTEGER - | '(' expr ')' - | '[' asm_addr ']' - ; - -asm_exprs - : asm_expr - | asm_exprs ',' asm_expr - ; - -asm_stmt - : asm_instr asm_exprs ';' - | asm_instr ';' - ; - -asm_block_stmt - : ASM '(' constant_expr ')' ';' - | ASM '(' constant_expr ')' AT_IDENT ';' - | ASM '{' asm_stmts '}' - | ASM AT_IDENT '{' asm_stmts '}' - | ASM '{' '}' - | ASM AT_IDENT '{' '}' - ; - -/* Order here matches compiler */ -statement - : compound_statement - | var_stmt - | declaration_stmt - | return_stmt - | if_stmt - | while_stmt - | defer_stmt - | switch_stmt - | do_stmt - | for_stmt - | foreach_stmt - | continue_stmt - | break_stmt - | nextcase_stmt - | asm_block_stmt - | ct_echo_stmt - | ct_assert_stmt - | ct_if_stmt - | ct_switch_stmt - | ct_foreach_stmt - | ct_for_stmt - | expr_no_list ';' - | assert_stmt - | ';' - ; - -compound_statement - : '{' opt_stmt_list '}' - ; - -statement_list - : statement - | statement_list statement - ; - -opt_stmt_list - : statement_list - | empty - ; - -switch_stmt - : SWITCH optional_label '{' switch_body '}' - | SWITCH optional_label '{' '}' - | SWITCH optional_label paren_cond opt_attributes '{' switch_body '}' - | SWITCH optional_label paren_cond opt_attributes '{' '}' - ; - -expression_list - : decl_or_expr - | expression_list ',' decl_or_expr - ; - -optional_label - : CONST_IDENT ':' - | empty - ; - -ct_assert_stmt - : CT_ASSERT constant_expr ':' constant_expr ';' - | CT_ASSERT constant_expr ';' - | CT_ERROR constant_expr ';' - ; - -ct_include_stmt - : CT_INCLUDE string_expr ';' - ; - -ct_echo_stmt - : CT_ECHO constant_expr ';' - ; - -bitstruct_declaration - : BITSTRUCT TYPE_IDENT opt_interface_impl ':' type_non_generic opt_attributes bitstruct_body - ; - -bitstruct_body - : '{' '}' - | '{' bitstruct_defs '}' - | '{' bitstruct_simple_defs '}' - ; - -bitstruct_defs - : bitstruct_def - | bitstruct_defs bitstruct_def - ; - -bitstruct_simple_defs - : base_type IDENT ';' - | bitstruct_simple_defs base_type IDENT ';' - ; - -bitstruct_def - : base_type IDENT ':' constant_expr DOTDOT constant_expr ';' - | base_type IDENT ':' constant_expr ';' - ; - -attribute_name - : AT_IDENT - | AT_TYPE_IDENT - | path AT_TYPE_IDENT - ; - -attribute_operator_expr - : '&' '[' ']' - | '[' ']' '=' - | '[' ']' - ; - -attr_param - : attribute_operator_expr - | constant_expr - ; - -attribute_param_list - : attr_param - | attribute_param_list ',' attr_param - ; - -attribute - : attribute_name - | attribute_name '(' attribute_param_list ')' - ; - -attribute_list - : attribute - | attribute_list attribute - ; - -opt_attributes - : attribute_list - | empty - ; - -trailing_block_param - : AT_IDENT - | AT_IDENT '(' ')' - | AT_IDENT '(' parameters ')' - ; - -macro_params - : parameters - | parameters ';' trailing_block_param - | ';' trailing_block_param - | empty - ; - -macro_func_body - : implies_body ';' - | compound_statement - ; - -macro_declaration - : MACRO macro_header '(' macro_params ')' opt_attributes macro_func_body - ; - -struct_or_union - : STRUCT - | UNION - ; - -struct_declaration - : struct_or_union TYPE_IDENT opt_interface_impl opt_attributes struct_body - ; - -struct_body - : '{' struct_declaration_list '}' - ; - -struct_declaration_list - : struct_member_decl - | struct_declaration_list struct_member_decl - ; - -enum_params - : enum_param_decl - | enum_params ',' enum_param_decl - ; - -struct_member_decl - : type identifier_list opt_attributes ';' - | struct_or_union IDENT opt_attributes struct_body - | struct_or_union opt_attributes struct_body - | BITSTRUCT ':' type_non_generic opt_attributes bitstruct_body - | BITSTRUCT IDENT ':' type_non_generic opt_attributes bitstruct_body - | INLINE type IDENT opt_attributes ';' - | INLINE type opt_attributes ';' - ; - - -enum_spec - : ':' base_type_non_generic '(' enum_params ')' - | ':' INLINE base_type_non_generic '(' enum_params ')' - | ':' base_type_non_generic - | ':' INLINE base_type_non_generic - | ':' '(' enum_params ')' - ; - -enum_declaration - : ENUM TYPE_IDENT opt_interface_impl enum_spec opt_attributes '{' enum_list '}' - | ENUM TYPE_IDENT opt_interface_impl opt_attributes '{' enum_list '}' - ; - -faults - : CONST_IDENT - | faults ',' CONST_IDENT - ; - -fault_declaration - : FAULT TYPE_IDENT opt_interface_impl opt_attributes '{' faults '}' - | FAULT TYPE_IDENT opt_interface_impl opt_attributes '{' faults ',' '}' - ; - -func_macro_name - : IDENT - | AT_IDENT - ; - -func_header - : optional_type type '.' func_macro_name - | optional_type func_macro_name - ; - -macro_header - : func_header - | type '.' func_macro_name - | func_macro_name - ; - -fn_parameter_list - : '(' parameters ')' - | '(' ')' - ; - -parameter_default - : parameter - | parameter '=' expr - | parameter '=' type - ; - -parameters - : parameter_default - | parameters ',' parameter_default - | parameters ',' - ; - -parameter - : type IDENT opt_attributes - | type ELLIPSIS IDENT opt_attributes - | type ELLIPSIS CT_IDENT - | type CT_IDENT - | type ELLIPSIS opt_attributes - | type HASH_IDENT opt_attributes - | type '&' IDENT opt_attributes - | type opt_attributes - | '&' IDENT opt_attributes - | HASH_IDENT opt_attributes - | ELLIPSIS - | IDENT opt_attributes - | IDENT ELLIPSIS opt_attributes - | CT_IDENT - | CT_IDENT ELLIPSIS - ; - -func_definition_decl - : FN func_header fn_parameter_list opt_attributes ';' - ; - -func_definition - : func_definition_decl - | FN func_header fn_parameter_list opt_attributes macro_func_body - ; - -const_declaration - : CONST CONST_IDENT opt_attributes '=' expr ';' - | CONST optional_type CONST_IDENT opt_attributes '=' expr ';' - | CONST optional_type CONST_IDENT opt_attributes ';' - ; - -func_typedef - : FN optional_type fn_parameter_list - ; - -opt_inline - : INLINE - | empty - ; - -generic_parameters - : expr - | type - | generic_parameters ',' expr - | generic_parameters ',' type - ; - -typedef_type - : func_typedef - | type - ; - -multi_declaration - : ',' IDENT - | multi_declaration ',' IDENT - ; - -global_storage - : TLOCAL - | empty - ; - -global_declaration - : global_storage optional_type IDENT opt_attributes ';' - | global_storage optional_type IDENT multi_declaration opt_attributes ';' - | global_storage optional_type IDENT opt_attributes '=' expr ';' - ; - -define_attribute - : AT_TYPE_IDENT '(' parameters ')' opt_attributes '=' '{' opt_attributes '}' - | AT_TYPE_IDENT opt_attributes '=' '{' opt_attributes '}' - ; - -generic_expr - : '{' generic_parameters '}' - ; - -opt_generic_parameters - : generic_expr - | empty - ; - -define_ident - : IDENT '=' path_ident opt_generic_parameters - | CONST_IDENT '=' path_const opt_generic_parameters - | AT_IDENT '=' path_at_ident opt_generic_parameters - ; - -define_declaration - : DEF define_ident opt_attributes ';' - | DEF define_attribute opt_attributes ';' - | DEF TYPE_IDENT opt_attributes '=' typedef_type opt_attributes ';' - ; - -interface_body - : func_definition_decl - | interface_body func_definition_decl - ; - -interface_declaration - : INTERFACE interface_declaration_name '{' '}' - | INTERFACE interface_declaration_name '{' interface_body '}' - ; - -interface_parents - : TYPE_IDENT - | interface_parents ',' TYPE_IDENT - ; - -interface_declaration_name - : TYPE_IDENT - | TYPE_IDENT ':' interface_parents - ; - -distinct_declaration - : DISTINCT TYPE_IDENT opt_interface_impl opt_attributes '=' opt_inline type ';' - ; - -module_param - : CONST_IDENT - | TYPE_IDENT - ; - -module_params - : module_param - | module_params ',' module_param - ; - -module - : MODULE path_ident opt_attributes ';' - | MODULE path_ident LGENPAR module_params RGENPAR opt_attributes ';' - ; - -import_paths - : path_ident - | import_paths ',' path_ident - ; - -import_decl - : IMPORT import_paths opt_attributes ';' - ; - -translation_unit - : top_level_statements - | empty - ; - -top_level_statements - : top_level - | top_level_statements top_level - ; - -opt_extern - : EXTERN - | empty - ; - -exec_decl - : CT_EXEC '(' expr ')' opt_attributes ';' - | CT_EXEC '(' expr ',' initializer_list ')' opt_attributes ';' - | CT_EXEC '(' expr ',' initializer_list ',' expr ')' opt_attributes ';' - ; - -top_level - : module - | import_decl - | exec_decl - | opt_extern func_definition - | opt_extern const_declaration - | opt_extern global_declaration - | ct_assert_stmt - | ct_echo_stmt - | ct_include_stmt - | struct_declaration - | fault_declaration - | enum_declaration - | macro_declaration - | define_declaration - | bitstruct_declaration - | distinct_declaration - | interface_declaration - ; - -%% - -void yyerror(YYLTYPE * yylloc_param , yyscan_t yyscanner, const char *yymsgp) -{ - fflush(stdout); - printf(":%d:%d:\n%*s\n%*s\n", yylloc_param->first_line, - yylloc_param->first_column, - yylloc_param->first_column, "^", yylloc_param->first_column, yymsgp); -} - -int main(int argc, char *argv[]) -{ - int rc; - yyscan_t scanner; - rc = yylex_init (&scanner); - if(rc) { - printf(" Failed to initialize the scanner: %d\n", rc); - return rc; - } - rc = yyparse (scanner); - yylex_destroy (scanner); - printf(" -> yyparse return %d\n", rc); - return rc; -} diff --git a/resources/project_schema.json b/resources/project_schema.json index cf99f6fb4..5709b03f9 100644 --- a/resources/project_schema.json +++ b/resources/project_schema.json @@ -199,6 +199,15 @@ "description": "Include the standard library.", "default": true }, + "linux-libc": { + "type": "string", + "description": "Set the libc to use for Linux.", + "enum": [ + "gnu", + "musl" + ], + "default": "gnu" + }, "x86cpu": { "type": "string", "description": "Set general level of x64 cpu.", diff --git a/resources/testproject/lib/clib.c3l/manifest.json b/resources/testproject/lib/clib.c3l/manifest.json index c5c4d498d..de3a8bff3 100644 --- a/resources/testproject/lib/clib.c3l/manifest.json +++ b/resources/testproject/lib/clib.c3l/manifest.json @@ -1,15 +1,19 @@ -{ - "provides" : "clib", - "c-sources" : ["hello2.c", "whitespace test.c"], - "targets" : { - "macos-x64" : { - }, - "macos-aarch64" : {}, - "linux-x64" : { +{ + "provides": "clib", + "c-sources": [ + "hello2.c", + "whitespace test.c" + ], + "targets": { + "macos-x64": {}, + "macos-aarch64": {}, + "linux-x64": { "cflags": "-fPIE" }, - "windows-x64" : { - "c-include-dirs": ["C:\\"] + "windows-x64": { + "c-include-dirs": [ + "C:\\" + ] } } } diff --git a/resources/testproject/lib/clib2.c3l b/resources/testproject/lib/clib2.c3l deleted file mode 100644 index ec52baeabfde9e43114f77804b7ca90487d14ced..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1168 zcmWIWW@Zs#-~hs;#8(jvP~Zoo*%=fVGE#GL^7WEKLwFh3E#vyqCil%uYX;)d3T_5Q zmamKq3_#5c48iBlc%Res^$gvhspom}%=Ob79&4RG?-O{!mo>C!!9YxXy6}&SdTKnsqH^D?@-cJ4bGe%LPxMp&&N|V0E1l zP=*uey5yY9BqP0K<4m~wTCuzD^jUw+v!0{8U3p>4 zGbXT8rnHrWngA^WS%`2-+rCfmfVu*d;RQM+H!&|WEw#8rFRM5|5A2*?pi?FSF^EPB zuF!M4`3@QIuwIy1)B1F0qC-dH+{RwnQjWY^Zd|5Czb38vW1YEBt7o74w)ZSt4DpBd zYUemuFi$G)XHF~jvno*k(rA6{TJ=5QXWZM|v~KH}EVWeicb555VU-tortYM~!e6IX zS6nZ7{QuIQonMx5&8pU(G%NAd($lxUHod+o%ePLm;>JHmAF`1*u>;1BBvXkeNk!K^MI z&G^w&f$fu|r9=l)pQ56pfLO$FaRo8Q;6ps3;t2^8yw07!>aC-3!t?5BPaQo?T|Zw> zPaV%tK906o2blu(*@LFfo)I%;KKB&8YubKiJ$>~~o;lC$b;jGjbyX_6AP-D~i^$A@ZYXl10;OUYSkgET$Rs*VBO41!k;w4~N|7+Iq*0TRfwc6AZZvWb gff51?ENSFrVjw$N1bDNuflOin!d##ed6_{x03$tO$^ZZW diff --git a/resources/testproject/lib/clib2.c3l/__MACOSX/._manifest.json b/resources/testproject/lib/clib2.c3l/__MACOSX/._manifest.json new file mode 100644 index 0000000000000000000000000000000000000000..a165526264b051e2436190185173d5264c39d5ea GIT binary patch literal 264 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@iia@@)0=NG0dz>LnHw#H7N@49B$lKq2Lwa(FtPw?pn5rwy4=L%qWoN- zbg^D>YEEi$NoIatP-0$sDpV~ykY;3HkU>*hmRX#cl#}Y2my%k+z|h$@GYzDkecx=b JyDY6N4FFgJEJ*+W literal 0 HcmV?d00001 diff --git a/resources/testproject/lib/clib2.c3l/clib2.c3i b/resources/testproject/lib/clib2.c3l/clib2.c3i new file mode 100644 index 000000000..0b289631e --- /dev/null +++ b/resources/testproject/lib/clib2.c3l/clib2.c3i @@ -0,0 +1,3 @@ +module clib2; + +extern fn void hello_from_c_zip(); diff --git a/resources/testproject/lib/clib2.c3l/hello.c b/resources/testproject/lib/clib2.c3l/hello.c new file mode 100644 index 000000000..384e83cb0 --- /dev/null +++ b/resources/testproject/lib/clib2.c3l/hello.c @@ -0,0 +1,5 @@ +#include +void hello_from_c_zip(void) +{ + puts("Hello from C Zip!"); +} \ No newline at end of file diff --git a/resources/testproject/lib/clib2.c3l/manifest.json b/resources/testproject/lib/clib2.c3l/manifest.json new file mode 100644 index 000000000..00c4ff735 --- /dev/null +++ b/resources/testproject/lib/clib2.c3l/manifest.json @@ -0,0 +1,14 @@ +{ + "provides": "clib2", + "c-sources": [ + "hello.c" + ], + "targets": { + "macos-x64": {}, + "macos-aarch64": {}, + "linux-x64": { + "cflags-override": "-fPIE" + }, + "windows-x64": {} + } +} diff --git a/src/build/build.h b/src/build/build.h index 3fca9d36f..215ca6627 100644 --- a/src/build/build.h +++ b/src/build/build.h @@ -103,6 +103,13 @@ typedef enum LINKER_TYPE_CUSTOM = 2, } LinkerType; +typedef enum +{ + LINUX_LIBC_NOT_SET = -1, + LINUX_LIBC_GNU = 0, + LINUX_LIBC_MUSL = 1, +} LinuxLibc; + typedef enum { TRUST_NONE, @@ -607,6 +614,7 @@ typedef struct BuildOptions_ OptimizationLevel optlevel; SizeOptimizationLevel optsize; RiscvAbi riscv_abi; + LinuxLibc linux_libc; MemoryEnvironment memory_environment; SanitizeMode sanitize_mode; uint32_t max_vector_size; @@ -808,6 +816,7 @@ typedef struct } win; struct { + LinuxLibc libc; const char *crt; const char *crtbegin; } linuxpaths; @@ -878,6 +887,7 @@ static BuildTarget default_build_target = { .feature.panic_level = PANIC_NOT_SET, .win.crt_linking = WIN_CRT_DEFAULT, .win.def = NULL, + .linuxpaths.libc = LINUX_LIBC_GNU, .switchrange_max_size = DEFAULT_SWITCHRANGE_MAX_SIZE, .switchjump_max_size = DEFAULT_SWITCH_JUMP_MAX_SIZE, .quiet = false, diff --git a/src/build/build_internal.h b/src/build/build_internal.h index 36481e251..fc324dee1 100644 --- a/src/build/build_internal.h +++ b/src/build/build_internal.h @@ -50,6 +50,11 @@ static const char *optsizes[3] = { [SIZE_OPTIMIZATION_TINY] = "tiny", }; +static const char *linuxlibc[2] = { + [LINUX_LIBC_GNU] = "gnu", + [LINUX_LIBC_MUSL] = "musl", +}; + static const char *linker_kind[3] = { [LINKER_TYPE_BUILTIN] = "builtin", [LINKER_TYPE_CC] = "cc", diff --git a/src/build/build_options.c b/src/build/build_options.c index d7d15662f..becb169da 100644 --- a/src/build/build_options.c +++ b/src/build/build_options.c @@ -216,6 +216,7 @@ static void usage(bool full) print_opt("--macos-min-version ", "Set the minimum MacOS version to compile for."); print_opt("--macos-sdk-version ", "Set the MacOS SDK compiled for."); PRINTF(""); + print_opt("--linux-libc=", "Set the libc to use on Linux, defaults to gnu."); print_opt("--linux-crt ", "Set the directory to use for finding crt1.o and related files."); print_opt("--linux-crtbegin ", "Set the directory to use for finding crtbegin.o and related files."); PRINTF(""); @@ -861,6 +862,11 @@ static void parse_option(BuildOptions *options) options->fp_math = parse_opt_select(FpOpt, argopt, fp_math); return; } + if ((argopt = match_argopt("linux-libc"))) + { + options->linux_libc = parse_opt_select(LinuxLibc, argopt, linuxlibc); + return; + } if ((argopt = match_argopt("optsize"))) { options->optsize = parse_opt_select(SizeOptimizationLevel, argopt, optsizes); @@ -1495,6 +1501,7 @@ BuildOptions parse_arguments(int argc, const char *argv[]) .merge_functions = MERGE_FUNCTIONS_NOT_SET, .slp_vectorization = VECTORIZATION_NOT_SET, .loop_vectorization = VECTORIZATION_NOT_SET, + .linux_libc = LINUX_LIBC_NOT_SET, .files = NULL, .build_dir = NULL, .output_dir = NULL, diff --git a/src/build/builder.c b/src/build/builder.c index f44b6163a..b3a71265c 100644 --- a/src/build/builder.c +++ b/src/build/builder.c @@ -1,6 +1,7 @@ // Copyright (c) 2019-2023 Christoffer Lerno. All rights reserved. // Use of this source code is governed by a LGPLv3.0 // a copy of which can be found in the LICENSE file. +#include "build.h" #include "build_internal.h" void load_library_files(void) {} @@ -14,6 +15,13 @@ ArchOsTarget default_target = MACOS_X64; ArchOsTarget default_target = ANDROID_X86_64; #elif defined(__linux__) && __linux__ ArchOsTarget default_target = LINUX_X64; + #if (defined(__GLIBC__) && __GLIBC__) || (defined(__GLIBC_MINOR__) && __GLIBC_MINOR__) +#define LINUX_LIBC +LinuxLibc default_libc = LINUX_LIBC_GNU; + #elif defined(__DEFINED_va_list) +#define LINUX_LIBC +LinuxLibc default_libc = LINUX_LIBC_MUSL; + #endif #elif defined(__NetBSD__) ArchOsTarget default_target = NETBSD_X64; #elif defined(__FreeBSD__) @@ -30,12 +38,26 @@ ArchOsTarget default_target = MACOS_AARCH64; ArchOsTarget default_target = ANDROID_AARCH64; #elif defined(__linux__) && __linux__ ArchOsTarget default_target = LINUX_AARCH64; + #if (defined(__GLIBC__) && __GLIBC__) || (defined(__GLIBC_MINOR__) && __GLIBC_MINOR__) +#define LINUX_LIBC +LinuxLibc default_libc = LINUX_LIBC_GNU; + #elif defined(__DEFINED_va_list) +#define LINUX_LIBC +LinuxLibc default_libc = LINUX_LIBC_MUSL; + #endif #else ArchOsTarget default_target = ELF_AARCH64; #endif #elif defined(i386) || defined(__i386__) || defined(__i386) || defined(_M_IX86) #if defined(__linux__) && __linux__ ArchOsTarget default_target = LINUX_X86; + #if (defined(__GLIBC__) && __GLIBC__) || (defined(__GLIBC_MINOR__) && __GLIBC_MINOR__) +#define LINUX_LIBC +LinuxLibc default_libc = LINUX_LIBC_GNU; + #elif defined(__DEFINED_va_list) +#define LINUX_LIBC +LinuxLibc default_libc = LINUX_LIBC_MUSL; + #endif #elif defined(__FreeBSD__) ArchOsTarget default_target = FREEBSD_X86; #elif defined(__OpenBSD__) @@ -50,12 +72,26 @@ ArchOsTarget default_target = ELF_X86; #elif defined(__riscv32) #if defined(__linux__) && __linux__ ArchOsTarget default_target = LINUX_RISCV32; + #if (defined(__GLIBC__) && __GLIBC__) || (defined(__GLIBC_MINOR__) && __GLIBC_MINOR__) +#define LINUX_LIBC +LinuxLibc default_libc = LINUX_LIBC_GNU; + #elif defined(__DEFINED_va_list) +#define LINUX_LIBC +LinuxLibc default_libc = LINUX_LIBC_MUSL; + #endif #else ArchOsTarget default_target = ELF_RISCV32; #endif #elif defined(__riscv64) #if defined(__linux__) && __linux__ ArchOsTarget default_target = LINUX_RISCV64; + #if (defined(__GLIBC__) && __GLIBC__) || (defined(__GLIBC_MINOR__) && __GLIBC_MINOR__) +#define LINUX_LIBC +LinuxLibc default_libc = LINUX_LIBC_GNU; + #elif defined(__DEFINED_va_list) +#define LINUX_LIBC +LinuxLibc default_libc = LINUX_LIBC_MUSL; + #endif #else ArchOsTarget default_target = ELF_RISCV64; #endif @@ -63,6 +99,10 @@ ArchOsTarget default_target = ELF_RISCV64; ArchOsTarget default_target = ARCH_OS_TARGET_DEFAULT; #endif +#ifndef LINUX_LIBC +LinuxLibc default_libc = LINUX_LIBC_GNU; +#endif + bool command_accepts_files(CompilerCommand command) { switch (command) @@ -428,7 +468,7 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions * set_if_updated(target->feature.riscv_cpu_set, options->riscv_cpu_set); set_if_updated(target->feature.riscv_abi, options->riscv_abi); set_if_updated(target->feature.win_debug, options->win_debug); - + set_if_updated(target->linuxpaths.libc, options->linux_libc); set_if_updated(target->feature.pass_win64_simd_as_arrays, options->win_64_simd); OVERRIDE_IF_SET(output_dir); diff --git a/src/build/project.c b/src/build/project.c index 77a779da4..917a2e361 100644 --- a/src/build/project.c +++ b/src/build/project.c @@ -31,6 +31,7 @@ const char *project_default_keys[][2] = { {"linker-search-paths", "Linker search paths."}, {"linux-crt", "Set the directory to use for finding crt1.o and related files."}, {"linux-crtbegin", "Set the directory to use for finding crtbegin.o and related files."}, + {"linux-libc", "Set the libc to use for Linux. Valid options are 'gnu' and 'musl', default is 'gnu'"}, {"loop-vectorize", "Force enable/disable loop auto-vectorization."}, {"macos-min-version", "Set the minimum MacOS version to compile for."}, {"macos-sdk-version", "Set the MacOS SDK compiled for." }, @@ -115,6 +116,7 @@ const char* project_target_keys[][2] = { {"linker-search-paths-override", "Linker search paths for this target, overriding global settings."}, {"linux-crt", "Set the directory to use for finding crt1.o and related files."}, {"linux-crtbegin", "Set the directory to use for finding crtbegin.o and related files."}, + {"linux-libc", "Set the libc to use for Linux. Valid options are 'gnu' and 'musl', default is 'gnu'"}, {"loop-vectorize", "Force enable/disable loop auto-vectorization."}, {"macos-min-version", "Set the minimum MacOS version to compile for."}, {"macos-sdk-version", "Set the MacOS SDK compiled for." }, @@ -483,6 +485,10 @@ static void load_into_build_target(BuildParseContext context, JSONObject *json, // Linux crtbegin target->linuxpaths.crtbegin = get_string(context, json, "linux-crtbegin", target->linuxpaths.crtbegin); + // linux-libc + LinuxLibc linux_libc = GET_SETTING(LinuxLibc, "linux-libc", linuxlibc, "`gnu` or `musl`."); + if (linux_libc > -1) target->linuxpaths.libc = linux_libc; + // version target->version = get_string(context, json, "version", target->version); diff --git a/src/compiler/linker.c b/src/compiler/linker.c index b861b5930..9b64b9117 100644 --- a/src/compiler/linker.c +++ b/src/compiler/linker.c @@ -331,6 +331,7 @@ static const char *find_arch_glob_path(const char *glob_path, int file_len) static const char *get_linux_crt_arch_glob(void) { + if (compiler.build.linuxpaths.libc == LINUX_LIBC_MUSL) return "/usr/lib/*/crt1.o"; switch (compiler.build.arch_os_target) { case LINUX_X64: @@ -348,6 +349,7 @@ static const char *get_linux_crt_arch_glob(void) static const char *get_linux_crt_begin_arch_glob(void) { + if (compiler.build.linuxpaths.libc == LINUX_LIBC_MUSL) return "/usr/lib/gcc/*/*/crtbegin.o"; switch (compiler.build.arch_os_target) { case LINUX_X64: @@ -398,6 +400,56 @@ static const char *find_linux_crt_begin(void) return path; } +static const char *find_linux_ld(void) +{ + INFO_LOG("Environment Type ID: %d", compiler.platform.environment_type); + switch (compiler.platform.environment_type) + { + case ENV_TYPE_MUSL: + case ENV_TYPE_MUSLEABI: + case ENV_TYPE_MUSLEABIHF: + switch (compiler.platform.arch) + { + case ARCH_TYPE_ARM: return "--dynamic-linker=/lib/ld-musl-arm.so.1"; + case ARCH_TYPE_ARMB: return "--dynamic-linker=/lib/ld-musl-armeb.so.1"; + case ARCH_TYPE_AARCH64: return "--dynamic-linker=/lib/ld-musl-aarch64.so.1"; + case ARCH_TYPE_AARCH64_BE: return "--dynamic-linker=/lib/ld-musl-aarch64_be.so.1"; + case ARCH_TYPE_MIPS: return "--dynamic-linker=/lib/ld-musl-mips.so.1"; + case ARCH_TYPE_MIPSEL: return "--dynamic-linker=/lib/ld-musl-mipsel.so.1"; + case ARCH_TYPE_MIPS64: return "--dynamic-linker=/lib/ld-musl-mips64.so.1"; + case ARCH_TYPE_MIPS64EL: return "--dynamic-linker=/lib/ld-musl-mips64el.so.1"; + case ARCH_TYPE_PPC: return "--dynamic-linker=/lib/ld-musl-powerpc.so.1"; + case ARCH_TYPE_PPC64: return "--dynamic-linker=/lib/ld-musl-powerpc64.so.1"; + case ARCH_TYPE_RISCV32: return "--dynamic-linker=/lib/ld-musl-riscv32.so.1"; + case ARCH_TYPE_RISCV64: return "--dynamic-linker=/lib/ld-musl-riscv64.so.1"; + case ARCH_TYPE_X86: return "--dynamic-linker=/lib/ld-musl-i386.so.1"; + case ARCH_TYPE_X86_64: return "--dynamic-linker=/lib/ld-musl-x86_64.so.1"; + default: return "--dynamic-linker=/lib/ld-musl-unknown.so.1"; // a placeholder for now + } + UNREACHABLE; + break; + case ENV_TYPE_ANDROID: + return "--dynamic-linker=/system/ld-android.so"; + default: + switch (compiler.platform.arch) { + case ARCH_TYPE_ARM: return "--dynamic-linker=/lib/ld-linux.so.3"; + case ARCH_TYPE_AARCH64: return "--dynamic-linker=/lib/ld-linux-aarch64.so.1"; + case ARCH_TYPE_MIPS: return "--dynamic-linker=/lib/ld-linux-mipsn8.so.1"; + case ARCH_TYPE_MIPSEL: return "--dynamic-linker=/lib/ld-linux-mipsn8.so.1"; + case ARCH_TYPE_MIPS64: return "--dynamic-linker=/lib/ld-linux-mipsn8.so.1"; + case ARCH_TYPE_MIPS64EL: return "--dynamic-linker=/lib/ld-linux-mipsn8.so.1"; + case ARCH_TYPE_RISCV32: return "-dynamic-linker=/lib/ld-linux-riscv32-ilp32.so.1"; + case ARCH_TYPE_RISCV64: return "-dynamic-linker=/lib/ld-linux-riscv64-lp64.so.1"; + case ARCH_TYPE_SPARCV9: return "--dynamic-linker=/lib/ld-linux.so.2"; + case ARCH_TYPE_X86: return "--dynamic-linker=/lib64/ld-linux.so.2"; + case ARCH_TYPE_X86_64: return "--dynamic-linker=/lib64/ld-linux-x86-64.so.2"; + default: return "--dynamic-linkrt=/lib/ld-linux-unknown.so.2"; // another placeholder until we have all of them + } + UNREACHABLE; + } + UNREACHABLE; +} + static void linker_setup_linux(const char ***args_ref, Linker linker_type, bool is_dylib) { if (link_libc()) linking_add_link(&compiler.linking, "dl"); @@ -452,7 +504,7 @@ static void linker_setup_linux(const char ***args_ref, Linker linker_type, bool } add_concat_file_arg(crt_dir, "crtn.o"); add_concat_quote_arg("-L", crt_dir); - add_plain_arg("--dynamic-linker=/lib64/ld-linux-x86-64.so.2"); + add_plain_arg(find_linux_ld()); if (compiler.linking.link_math) linking_add_link(&compiler.linking, "m"); linking_add_link(&compiler.linking, "pthread"); linking_add_link(&compiler.linking, "c"); diff --git a/src/compiler/target.c b/src/compiler/target.c index c21b83a55..087d9d4ef 100644 --- a/src/compiler/target.c +++ b/src/compiler/target.c @@ -1172,35 +1172,41 @@ const char *arch_to_linker_arch(ArchType arch) UNREACHABLE; } -static char *arch_to_target_triple[ARCH_OS_TARGET_LAST + 1] = { - [FREEBSD_X86] = "i386-unknown-freebsd", - [OPENBSD_X86] = "i386-unknown-openbsd", - [NETBSD_X86] = "i386-unknown-netbsd", - [MCU_X86] = "i386-pc-elfiamcu", - [LINUX_X86] = "i386-unknown-linux", - [ELF_X86] = "i386-unknown-elf", - [MACOS_X64] = "x86_64-apple-macosx", - [LINUX_X64] = "x86_64-pc-linux-gnu", - [WINDOWS_X64] = "x86_64-pc-windows-msvc", - [MINGW_X64] = "x86_64-w64-windows-gnu", - [NETBSD_X64] = "x86_64-pc-netbsd", - [FREEBSD_X64] = "x86_64-pc-freebsd", - [OPENBSD_X64] = "x86_64-pc-openbsd", - [ELF_X64] = "x86_64-unknown-elf", - [ANDROID_AARCH64] = "aarch64-linux-android", - [ANDROID_X86_64] = "x86_64-linux-android", - [LINUX_AARCH64] = "aarch64-unknown-linux-gnu", - [IOS_AARCH64] = "aarch64-apple-ios", - [MACOS_AARCH64] = "aarch64-apple-macosx", - [ELF_AARCH64] = "aarch64-unknown-elf", - [WINDOWS_AARCH64] = "aarch64-pc-windows-msvc", - [LINUX_RISCV32] = "riscv32-unknown-linux", - [ELF_RISCV32] = "riscv32-unknown-elf", - [LINUX_RISCV64] = "riscv64-unknown-linux", - [ELF_RISCV64] = "riscv64-unknown-elf", - [ELF_XTENSA] = "xtensa-unknown-elf", - [WASM32] = "wasm32-unknown-unknown", - [WASM64] = "wasm64-unknown-unknown", +static char *arch_to_target_triple(ArchOsTarget target, LinuxLibc linux_libc) +{ + switch (target) + { + case FREEBSD_X86: return "i386-unknown-freebsd"; + case OPENBSD_X86: return "i386-unknown-openbsd"; + case NETBSD_X86: return "i386-unknown-netbsd"; + case MCU_X86: return "i386-pc-elfiamcu"; + case LINUX_X86: return linux_libc == LINUX_LIBC_MUSL ? "i386-unknown-linux-musl" : "i386-unknown-linux"; + case ELF_X86: return "i386-unknown-elf"; + case MACOS_X64: return "x86_64-apple-macosx"; + case LINUX_X64: return linux_libc == LINUX_LIBC_MUSL ? "x86_64-pc-linux-musl" : "x86_64-pc-linux-gnu"; + case WINDOWS_X64: return "x86_64-pc-windows-msvc"; + case MINGW_X64: return "x86_64-w64-windows-gnu"; + case NETBSD_X64: return "x86_64-pc-netbsd"; + case FREEBSD_X64: return "x86_64-pc-freebsd"; + case OPENBSD_X64: return "x86_64-pc-openbsd"; + case ELF_X64: return "x86_64-unknown-elf"; + case ANDROID_AARCH64: return "aarch64-linux-android"; + case ANDROID_X86_64: return "x86_64-linux-android"; + case LINUX_AARCH64: return linux_libc == LINUX_LIBC_MUSL ? "aarch64-unknown-linux-musl" : "aarch64-unknown-linux-gnu"; + case IOS_AARCH64: return "aarch64-apple-ios"; + case MACOS_AARCH64: return "aarch64-apple-macosx"; + case ELF_AARCH64: return "aarch64-unknown-elf"; + case WINDOWS_AARCH64: return "aarch64-pc-windows-msvc"; + case LINUX_RISCV32: return linux_libc == LINUX_LIBC_MUSL ? "riscv32-unknown-linux-musl" : "riscv32-unknown-linux"; + case ELF_RISCV32: return "riscv32-unknown-elf"; + case LINUX_RISCV64: return linux_libc == LINUX_LIBC_MUSL ? "riscv64-unknown-linux-musl" : "riscv64-unknown-linux"; + case ELF_RISCV64: return "riscv64-unknown-elf"; + case ELF_XTENSA: return "xtensa-unknown-elf"; + case WASM32: return "wasm32-unknown-unknown"; + case WASM64: return "wasm64-unknown-unknown"; + case ARCH_OS_TARGET_DEFAULT: UNREACHABLE; + } + UNREACHABLE; }; static bool arch_is_supported(ArchType arch) @@ -1323,6 +1329,7 @@ static EnvironmentType environment_type_from_llvm_string(StringSlice env) } } + INFO_LOG("Platform Environment: %s", env.ptr); #define STRCASE(_str, _arch) if (slice_strcmp(env, _str)) return _arch; STRCASE("gnu", ENV_TYPE_GNU) STRCASE("gnuabin32", ENV_TYPE_GNUABIN32) @@ -2139,7 +2146,7 @@ void target_setup(BuildTarget *target) } #endif - compiler.platform.target_triple = arch_to_target_triple[target->arch_os_target]; + compiler.platform.target_triple = arch_to_target_triple(target->arch_os_target, target->linuxpaths.libc); ASSERT(compiler.platform.target_triple); compiler.platform.alloca_address_space = 0; diff --git a/src/utils/hostinfo.c b/src/utils/hostinfo.c index 5b63196f2..78ece5edc 100644 --- a/src/utils/hostinfo.c +++ b/src/utils/hostinfo.c @@ -36,7 +36,7 @@ ArchType hostinfo_arch_type(void) #elif defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__) || defined(__ppc__) || defined(__PPC__) || defined(_ARCH_PPC) return ARCH_TYPE_PPC; #elif defined(__sparc__) || defined(__sparc) - return ARCH_UNSUPPORTED + return ARCH_UNSUPPORTED; #else return ARCH_TYPE_UNKNOWN; #endif