Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,17 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: crate-ci/typos@cfe759ac8dd421e203cc293a373396fbc6fe0d4b # v1.22.7

build-script-windows:
name: 'build.cmd'
runs-on: windows-2025-vs2026
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- run: .\build.cmd
- uses: actions/upload-artifact@v4
with:
Expand All @@ -39,6 +43,8 @@ jobs:
runs-on: windows-2025-vs2026
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: actions/download-artifact@v4
with:
name: cpp2b-windows-x86_64
Expand All @@ -56,6 +62,8 @@ jobs:
- run: rm ./llvm.sh
- run: sudo apt-get install libc++-19-dev ninja-build libclang-19-dev -y
- uses: actions/checkout@v4
with:
submodules: recursive
- run: ./build.sh
- uses: actions/upload-artifact@v4
with:
Expand All @@ -75,6 +83,8 @@ jobs:
- run: rm ./llvm.sh
- run: sudo apt-get install libc++-19-dev ninja-build libclang-19-dev -y
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: actions/download-artifact@v4
with:
name: cpp2b-linux-x86_64
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "cppfront"]
path = cppfront
url = https://github.com/hsutter/cppfront.git
20 changes: 18 additions & 2 deletions build.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ setlocal enabledelayedexpansion
set root_dir=%~dp0
set tools_dir=%~dp0.cache\tools\
set cppfront=%tools_dir%\cppfront.exe
set cppfront_include_dir=%~dp0.cache\repos\cppfront\include
set cppfront_include_dir=%~dp0cppfront\source
set cpp2b_dist=%~dp0dist\debug\cpp2b
set modules_dir=%~dp0.cache\modules

Expand Down Expand Up @@ -140,8 +140,23 @@ if %ERRORLEVEL% neq 0 (
exit %ERRORLEVEL%
)

echo INFO: compiling cpp2b_build_info_parser module...
pushd %modules_dir%
cl /nologo ^
/std:c++latest /W4 /MDd /EHsc ^
-I"%cppfront_include_dir%" ^
/reference "%modules_dir%\std.ifc" ^
/reference "%modules_dir%\std.compat.ifc" ^
/c /interface /TP "%root_dir%src\cpp2b_build_info_parser.cppm" > NUL
popd

if %ERRORLEVEL% neq 0 (
echo ERROR: failed to compile cpp2b_build_info_parser module
exit %ERRORLEVEL%
)

if not exist %cppfront% (
pushd .cache\repos\cppfront\source
pushd cppfront\source
echo INFO: compiling cppfront...
cl /nologo /std:c++latest /EHsc cppfront.cpp
xcopy cppfront.exe %tools_dir% /Y /Q
Expand All @@ -167,6 +182,7 @@ cl /nologo "%root_dir%.cache/cpp2/source/src/main.cpp" ^
/reference "%modules_dir%\dylib.ifc" "%modules_dir%\dylib.obj" ^
/reference "%modules_dir%\nlohmann.json.ifc" "%modules_dir%\nlohmann.json.obj" ^
/reference "%modules_dir%\cpp2b.ifc" "%modules_dir%\cpp2b.obj" ^
/reference "%modules_dir%\cpp2b_build_info_parser.ifc" "%modules_dir%\cpp2b_build_info_parser.obj" ^
/std:c++latest /W4 /MDd /EHsc ^
/DEBUG:FULL /Zi /FC ^
-I"%cppfront_include_dir%" ^
Expand Down
5 changes: 5 additions & 0 deletions build.cpp2
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import cpp2b.build;

cppfront :== "v0.8.1";

build: (inout b: cpp2b::build) -> void = {
_ = b.cpp1_module().source_path("src/dylib.cppm");
_ = b.cpp1_module().source_path("src/nlohmann.json.cppm");
_ = b.cpp1_module()
.source_path("src/cpp2b_build_info_parser.cppm")
.include_directory("cppfront/source");
b.binary_name("src/main", "cpp2b");
}
51 changes: 22 additions & 29 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -60,40 +60,13 @@ fi

log_info "using compiler '$CPP2B_COMPILER' version '$COMPILER_VERSION'"

function ensure_gh_repo() {
local repo=$1
local branch=$2
local repo_path=$ROOT_DIR/.cache/repos/$repo
if ! [ -d $repo_path ]; then
mkdir -p $repo_path
git clone --quiet --depth=1 --branch=$branch --filter=blob:none --sparse https://github.com/$repo $repo_path
fi
}

function ensure_gh_repo_subdir() {
local repo=$1
local repo_path=$ROOT_DIR/.cache/repos/$repo
local repo_subdir=$2
local repo_subdir_path=$repo_path/$repo_subdir
if ! [ -d $repo_subdir_path ]; then
cd $repo_path
log_info "checking out repo $repo/$reposubdir"
git sparse-checkout add $repo_subdir
cd $ROOT_DIR
fi
}

ensure_gh_repo "hsutter/cppfront" "v0.8.1"
ensure_gh_repo_subdir "hsutter/cppfront" "source"
ensure_gh_repo_subdir "hsutter/cppfront" "include"

CPPFRONT_INCLUDE_DIR=$ROOT_DIR/.cache/repos/hsutter/cppfront/include
CPPFRONT_INCLUDE_DIR=$ROOT_DIR/cppfront/source

LLVM_ROOT=/usr/lib/llvm-$COMPILER_MAJOR_VERSION

if ! [ -x $CPPFRONT ]; then
log_info "compiling cppfront..."
cd $ROOT_DIR/.cache/repos/hsutter/cppfront/source
cd $ROOT_DIR/cppfront/source
$CPP2B_COMPILER \
-std=c++23 \
-stdlib=libc++ \
Expand Down Expand Up @@ -176,6 +149,20 @@ if ! [ -f $MODULES_DIR/nlohmann.json.pcm ]; then
cd $ROOT_DIR
fi

if ! [ -f $MODULES_DIR/cpp2b_build_info_parser.pcm ]; then
log_info "compiling cpp2b_build_info_parser module..."

$CPP2B_COMPILER \
-stdlib=libc++ \
-std=c++23 \
-fexperimental-library \
-isystem $LLVM_ROOT/include/c++/v1 \
-fprebuilt-module-path=$MODULES_DIR \
-I"$CPPFRONT_INCLUDE_DIR" \
"$ROOT_DIR/src/cpp2b_build_info_parser.cppm" \
--precompile -o $MODULES_DIR/cpp2b_build_info_parser.pcm
fi

log_info "compiling cpp2b module..."
if [ -f "$ROOT_DIR/.cache/cpp2/source/_build/cpp2b.cppm" ]; then
rm "$ROOT_DIR/.cache/cpp2/source/_build/cpp2b.cppm"
Expand All @@ -199,10 +186,16 @@ log_info "compiling..."
$CPP2B_COMPILER \
-g \
-stdlib=libc++ \
-fmodule-file=cpp2b="$MODULES_DIR/cpp2b.pcm" \
-fmodule-file=dylib="$MODULES_DIR/dylib.pcm" \
-fmodule-file=std.compat="$MODULES_DIR/std.compat.pcm" \
-fmodule-file=nlohmann.json="$MODULES_DIR/nlohmann.json.pcm" \
-fmodule-file=cpp2b_build_info_parser="$MODULES_DIR/cpp2b_build_info_parser.pcm" \
"$MODULES_DIR/cpp2b.pcm" \
"$MODULES_DIR/dylib.pcm" \
"$MODULES_DIR/std.compat.pcm" \
"$MODULES_DIR/nlohmann.json.pcm" \
"$MODULES_DIR/cpp2b_build_info_parser.pcm" \
"$ROOT_DIR/.cache/cpp2/source/src/main.cpp" \
-std=c++23 \
-fexperimental-library \
Expand Down
1 change: 1 addition & 0 deletions cppfront
Submodule cppfront added at ec1f98
135 changes: 135 additions & 0 deletions src/cpp2b_build_info_parser.cppm
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
module;
#include "parse.h"
export module cpp2b_build_info_parser;

import std;

export namespace cpp2b_build_info_parser {

enum class source_kind { unknown, module, binary, build };

struct source_info {
source_kind kind = source_kind::unknown;
std::string module_name;
std::vector<std::string> imports;
std::map<std::string, std::string> constants;
bool exported = false;
};

source_info parse_source(const std::string& filename) {
auto result = source_info{};
auto errors = std::vector<cpp2::error_entry>{};
auto source = cpp2::source{errors};

if(!source.load(filename)) {
return result;
}

// Extract imports from source lines
for(auto const& line : source.get_lines()) {
if(line.cat == cpp2::source_line::category::import) {
std::string text = line.text;
// Basic extraction: import <name> ;
size_t import_pos = text.find("import");
if(import_pos != std::string::npos) {
std::string import_name;
size_t k = import_pos + 6;
while(k < text.size() && std::isspace(text[k])) {
k++;
}
while(k < text.size() && !std::isspace(text[k]) && text[k] != ';') {
import_name += text[k];
k++;
}
if(!import_name.empty()) {
result.imports.emplace_back(import_name);
}
}
}
}

cpp2::tokens tokens(errors);
tokens.lex(source.get_lines());

std::vector<cpp2::token> all_tokens;
for(auto const& [line, line_tokens] : tokens.get_map()) {
for(auto const& t : line_tokens) {
all_tokens.push_back(t);
}
}

std::filesystem::path p(filename);
if(p.filename() == "build.cpp2") {
result.kind = source_kind::build;
// Extract constants
for(size_t j = 0; j < all_tokens.size(); ++j) {
// identifier == string_literal ;
if(j + 3 < all_tokens.size() &&
all_tokens[j].type() == cpp2::lexeme::Identifier &&
all_tokens[j + 1].type() == cpp2::lexeme::EqualComparison &&
all_tokens[j + 2].type() == cpp2::lexeme::StringLiteral &&
all_tokens[j + 3].type() == cpp2::lexeme::Semicolon) {
auto name = all_tokens[j].as_string_view();
auto value_raw = all_tokens[j + 2].as_string_view();
if(value_raw.size() >= 2) {
auto value = std::string(value_raw.substr(1, value_raw.size() - 2));
result.constants[std::string(name)] = value;
}
j += 3;
}
// identifier :== string_literal ;
else if (j + 3 < all_tokens.size() &&
all_tokens[j].type() == cpp2::lexeme::Identifier &&
all_tokens[j+1].type() == cpp2::lexeme::Colon &&
all_tokens[j+2].type() == cpp2::lexeme::EqualComparison &&
all_tokens[j+3].type() == cpp2::lexeme::StringLiteral) {
auto name = all_tokens[j].as_string_view();
auto value_raw = all_tokens[j+3].as_string_view();
if (value_raw.size() >= 2) {
auto value = std::string(value_raw.substr(1, value_raw.size() - 2));
result.constants[std::string(name)] = value;
}
j += 3;
}
// identifier : type == string_literal ;
else if (j + 5 < all_tokens.size() &&
all_tokens[j].type() == cpp2::lexeme::Identifier &&
all_tokens[j+1].type() == cpp2::lexeme::Colon &&
all_tokens[j+3].type() == cpp2::lexeme::EqualComparison &&
all_tokens[j+4].type() == cpp2::lexeme::StringLiteral &&
all_tokens[j+5].type() == cpp2::lexeme::Semicolon) {
auto name = all_tokens[j].as_string_view();
auto value_raw = all_tokens[j + 4].as_string_view();
if(value_raw.size() >= 2) {
auto value = std::string(value_raw.substr(1, value_raw.size() - 2));
result.constants[std::string(name)] = value;
}
j += 5;
}
}
} else {
// Module detection
for(size_t k = 0; k + 2 < all_tokens.size(); ++k) {
if(all_tokens[k].as_string_view() == "export" &&
all_tokens[k + 1].as_string_view() == "module" &&
all_tokens[k + 2].type() == cpp2::lexeme::Identifier) {
result.kind = source_kind::module;
result.module_name = std::string(all_tokens[k + 2].as_string_view());
result.exported = true;
return result;
}
}

// Binary detection
for(auto const& t : all_tokens) {
if(t.type() == cpp2::lexeme::Identifier && t.as_string_view() == "main") {
result.kind = source_kind::binary;
return result;
}
}
}

return result;
}

} // namespace cpp2b_build_info_parser
Loading
Loading