diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index b8cbaa2..6ef7801 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -7,6 +7,7 @@ env: # libcxx version to match whats already installed # https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2404-Readme.md LLVM_VERSION: '18.1.3' + CPP2B_LIBCXX_BUILD_ROOT: '/tmp/llvm-project/build' jobs: typos-check: @@ -24,7 +25,7 @@ jobs: - run: .\build.cmd - uses: actions/upload-artifact@v4 with: - name: cpp2b.exe + name: cpp2b-windows-latest path: dist/debug/cpp2b.exe if-no-files-found: error retention-days: 0 @@ -37,7 +38,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/download-artifact@v4 with: - name: 'cpp2b.exe' + name: cpp2b-windows-latest - run: .\cpp2b.exe build - run: Copy-Item .\.cache\cpp2\bin\cpp2b.exe -Destination .\cpp2b-self.exe - run: .\cpp2b-self.exe build @@ -61,10 +62,10 @@ jobs: CC=clang-18 CXX=clang++-18 cmake -G Ninja -S runtimes -B build -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind" ninja -C build - uses: actions/checkout@v4 - - run: CPP2B_LIBCXX_BUILD_ROOT=/tmp/llvm-project/build CC=clang-18 ./build.sh + - run: CC=clang-18 ./build.sh - uses: actions/upload-artifact@v4 with: - name: cpp2b + name: cpp2b-ubuntu-24.04 path: dist/debug/cpp2b if-no-files-found: error retention-days: 0 @@ -81,7 +82,37 @@ jobs: - uses: actions/checkout@v4 - uses: actions/download-artifact@v4 with: - name: cpp2b + name: cpp2b-ubuntu-24.04 - run: chmod +x cpp2b - - run: CPP2B_LIBCXX_BUILD_ROOT=/tmp/llvm-project/build ./cpp2b build - - run: CPP2B_LIBCXX_BUILD_ROOT=/tmp/llvm-project/build ./.cache/cpp2/bin/cpp2b build + - run: ./cpp2b build + - run: ./.cache/cpp2/bin/cpp2b build + + build-examples: + name: build examples + needs: [build-script-windows, build-script-linux] + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + example: + - init + os: + - windows-latest + - ubuntu-24.04 + steps: + - uses: actions/cache/restore@v4 + if: "!contains(matrix.os, 'windows')" + with: + path: /tmp/llvm-project/build + key: 'libcxx-${{ env.LLVM_VERSION }}' + - uses: actions/checkout@v4 + - uses: actions/download-artifact@v4 + id: cpp2b-binary + with: + name: 'cpp2b-${{ matrix.os }}' + - run: 'chmod +x ../../cpp2b && ../../cpp2b build' + if: "!contains(matrix.os, 'windows')" + working-directory: "examples/${{ matrix.example }}" + - run: ..\..\cpp2b.exe build + if: "contains(matrix.os, 'windows')" + working-directory: 'examples/${{ matrix.example }}' diff --git a/examples/init/.gitignore b/examples/init/.gitignore new file mode 100644 index 0000000..e54e919 --- /dev/null +++ b/examples/init/.gitignore @@ -0,0 +1,2 @@ +# cpp2b cache directory +.cache/cpp2 diff --git a/examples/init/README.md b/examples/init/README.md new file mode 100644 index 0000000..79759c4 --- /dev/null +++ b/examples/init/README.md @@ -0,0 +1,5 @@ +This project is the result of running + +```bash +cpp2b init +``` diff --git a/examples/init/build.cpp2 b/examples/init/build.cpp2 new file mode 100644 index 0000000..698d1d9 --- /dev/null +++ b/examples/init/build.cpp2 @@ -0,0 +1,6 @@ +import cpp2b.build; + +build: (inout b: cpp2b::build) -> void = { + // rename binary so instead of it being 'src/main' it will be 'init' + b.binary_name("src/main", "init"); +} diff --git a/examples/init/src/main.cpp2 b/examples/init/src/main.cpp2 new file mode 100644 index 0000000..7338fd3 --- /dev/null +++ b/examples/init/src/main.cpp2 @@ -0,0 +1 @@ +main: () = std::println("Hello, init!"); diff --git a/src/main.cpp2 b/src/main.cpp2 index 464de7e..2613389 100644 --- a/src/main.cpp2 +++ b/src/main.cpp2 @@ -16,6 +16,10 @@ log_info: (fmt: std::format_string, forward args...: Arg std::println("\033[0;36mINFO\033[0m: {}", std::format(fmt, args...)); } +log_success: (fmt: std::format_string, forward args...: Args) = { + std::println("\033[0;32mSUCCESS\033[0m: {}", std::format(fmt, args...)); +} + ensure_dir: (dir: fs::path) = { status := fs::status(dir); @@ -358,6 +362,7 @@ main: (args) -> int = { return inspect arg -> int { is "build" = subcommands::build(remaining_args); is "clean" = subcommands::clean(remaining_args); + is "init" = subcommands::init(remaining_args); is "run" = subcommands::run(remaining_args); is _ = subcommands::unknown(arg); }; @@ -496,16 +501,21 @@ warn_if_error: (context, p: fs::path, ec: std::error_code) -> void = { } } + find_root_dir: (dir: fs::path) -> std::optional = { + return find_root_dir(dir, "build.cpp2"); +} + +find_root_dir: (dir: fs::path, filename) -> std::optional = { if dir.empty() { return std::nullopt; } - if fs::exists(dir / "build.cpp2") { + if fs::exists(dir / filename) { return dir; } if !dir.has_parent_path() { return std::nullopt; } - return find_root_dir(dir.parent_path()); + return find_root_dir(dir.parent_path(), filename); } build_binary_result: @struct type = { @@ -763,6 +773,15 @@ subcommands: type = { continue src_loop; } } + + if rel_path.has_parent_path() { + src_root_dir := find_root_dir(rel_path.parent_path()); + if src_root_dir && src_root_dir* != root_dir* { + log_warning("ignoring subproject source {} - this may change in the future", rel_path.generic_string()); + continue src_loop; + } + } + cpp2_source_files.emplace_back(rel_path); } else if p.extension() == ".cppm" { rel_path := fs::relative(p, fs::current_path()); @@ -771,6 +790,15 @@ subcommands: type = { continue src_loop; } } + + if rel_path.has_parent_path() { + src_root_dir := find_root_dir(rel_path.parent_path()); + if src_root_dir && src_root_dir* != root_dir* { + log_warning("ignoring subproject source {} - this may change in the future", rel_path.generic_string()); + continue src_loop; + } + } + cpp1_module_source_files.emplace_back(rel_path); } } @@ -905,7 +933,7 @@ subcommands: type = { return build_result.exit_code; } - log_info("binary built {} ({}ms)", fs::relative(build_result.outpath).generic_string(), build_result.duration.count()); + log_success("binary built {} ({}ms)", fs::relative(build_result.outpath).generic_string(), build_result.duration.count()); } return 0; @@ -926,6 +954,55 @@ subcommands: type = { return 0; } + init: (args) -> int = { + if fs::exists("build.cpp2") { + log_error("already initialized cpp2b project!"); + return 1; + } + + dirname := fs::current_path().filename().string(); + + ensure_dir("src"); + + main_cpp2: std::ofstream = ("src/main.cpp2", std::ios::binary); + main_cpp2 << "main: () = std::println(\"Hello, (dirname)$!\");\n"; + + build_cpp2: std::ofstream = ("build.cpp2", std::ios::binary); + build_cpp2 << "import cpp2b.build;\n\n"; + build_cpp2 << "build: (inout b: cpp2b::build) -> void = {\n"; + build_cpp2 << "\t// rename binary so instead of it being 'src/main' it will be '(dirname)$'\n"; + build_cpp2 << "\tb.binary_name(\"src/main\", \"(dirname)$\");\n"; + build_cpp2 << "}\n"; + + main_cpp2.flush(); + main_cpp2.close(); + build_cpp2.flush(); + build_cpp2.close(); + + log_info("added build.cpp2"); + log_info("added src/main.cpp2"); + + if !fs::exists(".gitignore") { + if !find_root_dir(fs::current_path(), ".git") { + log_warning("assuming git repository"); + } + + gitignore: std::ofstream = (".gitignore", std::ios::binary); + gitignore << "# cpp2b cache directory\n"; + gitignore << ".cache/cpp2\n"; + + gitignore.flush(); + gitignore.close(); + + log_info("added .gitignore"); + } + + log_success("initialized cpp2b project '{}'", dirname); + log_info("run `cpp2b build` to build your project"); + + return 0; + } + unknown: (subcommand) -> int = { log_error("unknown subcommand {}", subcommand); return 1;