From b1b3ad2aaab6176d57b46ad8aaf07e651a504fe8 Mon Sep 17 00:00:00 2001 From: Trouble-Truffle Date: Wed, 13 Dec 2023 08:24:55 +0800 Subject: [PATCH 1/2] fix: Make crt*.o files also located by dlopen --- .envrc | 1 + .gitignore | 5 +- CMakeLists.txt | 8 +-- flake.lock | 59 ++++++++++++++++++ flake.nix | 105 +++++++++++++++++++++++++++++++++ src/builder/linker/linux/ld.cc | 66 ++++++++++++++++++--- 6 files changed, 230 insertions(+), 14 deletions(-) create mode 100644 .envrc create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/.envrc b/.envrc new file mode 100644 index 00000000..3550a30f --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.gitignore b/.gitignore index 5e55dc2a..06799610 100644 --- a/.gitignore +++ b/.gitignore @@ -69,4 +69,7 @@ install_manifest.txt compile_commands.json callgrind.out.* -install_deps_temp/ \ No newline at end of file +install_deps_temp/ +result +.direnv/ +.cmake/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 83275638..f7470b08 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -258,11 +258,7 @@ if (DEFINED ENV{BUILD_FOR_CE}) add_compile_definitions(_SNOWBALL_BUILD_FOR_CE="1") endif() -if (${BUILD_FOR_WIN}) - add_compile_definitions(LD_PATH="ld") -else() - add_compile_definitions(LD_PATH="/usr/bin/ld") -endif() +add_compile_definitions(LD_PATH="ld") add_compile_definitions(STATICLIB_DIR="${STATICLIB_DIR}") @@ -353,4 +349,4 @@ install(TARGETS snowballexe EXPORT MyLibConfig # TODO: as a feature: # install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}) -#install(FILES ${std_sn_files} DESTINATION ${HOME_DIR}/${STATICLIB_DIR}/${_SNOWBALL_LIBRARY_DIR}) \ No newline at end of file +#install(FILES ${std_sn_files} DESTINATION ${HOME_DIR}/${STATICLIB_DIR}/${_SNOWBALL_LIBRARY_DIR}) diff --git a/flake.lock b/flake.lock new file mode 100644 index 00000000..ffea064b --- /dev/null +++ b/flake.lock @@ -0,0 +1,59 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1701680307, + "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1702272962, + "narHash": "sha256-D+zHwkwPc6oYQ4G3A1HuadopqRwUY/JkMwHz1YF7j4Q=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e97b3e4186bcadf0ef1b6be22b8558eab1cdeb5d", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "type": "indirect" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 00000000..8a220235 --- /dev/null +++ b/flake.nix @@ -0,0 +1,105 @@ +{ + description = "Snowball is a low-weight, statically typed, object oriented programming language. "; + + inputs = { + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { + self, + flake-utils, + nixpkgs, + ... + }: + flake-utils.lib.eachDefaultSystem (system: let + pkgs = import nixpkgs {inherit system;}; + in { + packages.snowball = pkgs.stdenv.mkDerivation { + name = "snowball"; + version = "0.0.8"; + + src = ./.; + + nativeBuildInputs = with pkgs; [cmake pkg-config makeWrapper]; + buildInputs = with pkgs; [zstd libxml2 libsigsegv glib pcre2 libllvm libbacktrace]; + + patchPhase = '' + sed -i -e '/CPMAddPackage(/,/)/d' CMakeLists.txt + sed -i -e 's/app\///' app/*.cc + sed -i -e 's/app\///' app/commands/*.h + ''; + + buildPhase = '' + runHook preBuild + + mkdir -p bin/Release + + #HACK: uses RelWithDebInfo since normal realease causes a segfault + cmake \ + -DLLVM_ENABLE_BACKTRACES=OFF \ + -DLLVM_ENABLE_PER_TARGET_RUNTIME_DIR=OFF \ + -DLLVM_ENABLE_TERMINFO=OFF \ + -DCMAKE_OSX_ARCHITECTURES="${system}" \ + -DLLVM_ENABLE_ZLIB=OFF \ + -DLLVM_INCLUDE_EXAMPLES=OFF \ + -DLLVM_INCLUDE_DOCS=OFF \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DEXECUTABLE_OUTPUT_PATH="bin/Release" $@ . + + cmake --build . --config RelWithDebInfo -- -j $NIX_BUILD_CORES + + runHook postBuild + ''; + installPhase = '' + runHook preInstall + + install --mode +x -D ./bin/Release/snowball $out/bin/unwrapped/snowball + install --mode +x -D ./libSnowball.so $out/lib/libSnowball.so + install --mode +x -D ./libsnowballrt.so $out/lib/libsnowballrt.so + cp -r $src/stdlib "$out" + + wrapProgram "$out/bin/unwrapped/snowball" --suffix LD_LIBRARY_PATH ':' "$out/lib" + + cat < "$out/bin/snowball" + #!/bin/sh + if [ ! -d "\$HOME/.snowball/stdlib" ]; then + echo -e "\x1b[32mCreating \$HOME/.snowball/stdlib\x1b[0m" + mkdir "\$HOME/.snowball" + cp -r "$out/stdlib" "\$HOME/.snowball/stdlib" + fi + + exec "$out/bin/unwrapped/snowball" \$@ + EOF + + chmod +x "$out/bin/snowball" + runHook postInstall + ''; + + meta = { + description = "Snowball is a low-weight, statically typed, object oriented programming language"; + homepage = "https://github.com/snowball-lang/snowball"; + license = pkgs.lib.licenses.mit; + platforms = pkgs.lib.platforms.all; + }; + }; + + packages.default = self.packages.${system}.snowball; + + devShells.default = pkgs.mkShell { + packages = with pkgs; [ + zstd + libsigsegv + cmake + pkg-config + glib + pcre2 + libllvm + libbacktrace + libxml2 + clang-tools + cmake-language-server + cppcheck + ]; + }; + }); +} diff --git a/src/builder/linker/linux/ld.cc b/src/builder/linker/linux/ld.cc index 42fe5fa8..4f13db83 100644 --- a/src/builder/linker/linux/ld.cc +++ b/src/builder/linker/linux/ld.cc @@ -1,8 +1,10 @@ // only generate for linux #if defined(__linux__) || defined(__gnu_linux__) || defined(__linux) || defined(__LINUX__) +#include "../../../ast/errors/error.h" #include "../../../constants.h" #include "../Linker.h" +#include #include namespace fs = std::filesystem; @@ -14,7 +16,7 @@ void Linker::constructLinkerArgs(std::string& input, std::string& output, std::v const bool isIAMCU = target.isOSIAMCU(); linkerArgs.clear(); if (ctx->isDynamic) { - //linkerArgs.push_back("-pic"); + // linkerArgs.push_back("-pic"); linkerArgs.push_back("--export-dynamic"); linkerArgs.push_back("-m"); linkerArgs.push_back("elf_x86_64"); @@ -30,16 +32,66 @@ void Linker::constructLinkerArgs(std::string& input, std::string& output, std::v if (ctx->withStd) { // TODO: check if this works for all platforms linkerArgs.push_back("-dynamic-linker"); - linkerArgs.push_back("/lib64/ld-linux-x86-64.so.2"); + + fs::path ld_linux_path; + + void* ld_linux_handle = dlopen("ld-linux-x86-64.so.2", RTLD_LAZY); + if (!ld_linux_handle) { Syntax::E(FMT("Error getting library path: %s", dlerror())); } + + Dl_info ld_linux_info; + if (dladdr(ld_linux_handle, &ld_linux_info)) { + ld_linux_path = ld_linux_info.dli_fname; + } else { + Syntax::E(FMT("Error getting library path: %s", dlerror())); + } + linkerArgs.push_back(ld_linux_path); auto path = std::string("/usr") + PATH_SEPARATOR + _SNOWBALL_LIBRARY_OBJ; auto triple = getPlatformTriple(); assert(!triple.empty() && "Unsupported platform for linking!"); - auto platformPath = fs::path(path) / triple; - linkerArgs.push_back(platformPath / "crt1.o"); - linkerArgs.push_back(platformPath / "crti.o"); + + if (!dlopen("crt1.o", RTLD_LAZY)) { + // dlopen returns `/crt1.o: only ET_DYN and ET_EXEC can be loaded` + // this is abusing that fact to get the absolute path + std::string err = dlerror(); + std::size_t delim = err.find(':'); + if (delim != std::string::npos) { + linkerArgs.push_back(err.substr(0, delim)); + } else { + Syntax::E(err); + } + } else { + Syntax::E("crt1.o was loaded as a shared library"); + } + + if (!dlopen("crti.o", RTLD_LAZY)) { + // dlopen returns `/crt1.o: only ET_DYN and ET_EXEC can be loaded` + // this is abusing that fact to get the absolute path + std::string err = dlerror(); + std::size_t delim = err.find(':'); + if (delim != std::string::npos) { + linkerArgs.push_back(err.substr(0, delim)); + } else { + Syntax::E(err); + } + } else { + Syntax::E("crti.o was loaded as a shared library"); + } + if (!isIAMCU) { - linkerArgs.push_back(platformPath / "crtn.o"); + if (!dlopen("crtn.o", RTLD_LAZY)) { + // dlopen returns `/crt1.o: only ET_DYN and ET_EXEC can be loaded` + // this is abusing that fact to get the absolute path + std::string err = dlerror(); + std::size_t delim = err.find(':'); + if (delim != std::string::npos) { + linkerArgs.push_back(err.substr(0, delim)); + } else { + Syntax::E(err); + } + } else { + Syntax::E("crtn.o was loaded as a shared library"); + } } else { // TODO: add crtbegin.o and crtend.o } @@ -84,4 +136,4 @@ std::string Linker::getSharedLibraryName(std::string& library) { return library } // namespace linker } // namespace snowball -#endif \ No newline at end of file +#endif From 79f2fbc9315568cc9e8d53fb816b9a178230f9b3 Mon Sep 17 00:00:00 2001 From: Perigord <90542764+Perigord-Kleisli@users.noreply.github.com> Date: Thu, 14 Dec 2023 14:59:47 +0800 Subject: [PATCH 2/2] feat(build): import version from ./snowball.version.str Signed-off-by: Perigord <90542764+Perigord-Kleisli@users.noreply.github.com> --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 8a220235..c0d6ecef 100644 --- a/flake.nix +++ b/flake.nix @@ -16,7 +16,7 @@ in { packages.snowball = pkgs.stdenv.mkDerivation { name = "snowball"; - version = "0.0.8"; + version = pkgs.lib.strings.readFile ./snowball.version.str; src = ./.;