Skip to content

Commit ac0116a

Browse files
authored
Feature/nbrf (#23)
* Add nanobind extension for nob. * Add template to run nob command via Python and to CI. * Add basic robot framework test. * Start fixing memory leaks in nob (WIP, cf. TODO) * Update duplicate code action.
1 parent e6881b8 commit ac0116a

13 files changed

+165
-24
lines changed

.github/workflows/github-actions-duplicate-code-check.yml

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ on: pull_request
55
jobs:
66
duplicate-code-check:
77
name: Check for duplicate code
8-
runs-on: ubuntu-20.04
8+
run_if:
9+
if: startsWith(github.head_ref, 'adventofcode')
10+
runs-on: ubuntu-latest
911
steps:
1012
- name: Check for duplicate code
1113
uses: platisd/duplicate-code-detection-tool@master

.github/workflows/nanobind.yaml

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
name: nanobind
2+
run-name: ${{ github.actor }} is building Python extensions with nanobind
3+
on:
4+
push:
5+
workflow_dispatch:
6+
jobs:
7+
build:
8+
runs-on: ubuntu-latest
9+
defaults:
10+
run:
11+
shell: sh
12+
working-directory: .
13+
steps:
14+
- name: Checkout
15+
uses: actions/checkout@v4
16+
with:
17+
submodules: 'recursive'
18+
#- name: Setup tmate session
19+
# uses: mxschmitt/action-tmate@v3
20+
# with:
21+
# detached: true
22+
- name: Python setup
23+
uses: actions/setup-python@v5
24+
with:
25+
python-version: '3.11.9'
26+
- name: Install Python development dependency
27+
run: |
28+
sudo apt-get update
29+
sudo apt-get install python3.11-dev
30+
python -m pip install --upgrade pip
31+
pip install robotframework
32+
# pip install -r requirements.txt
33+
- name: Build
34+
run: ./build_nb.sh
35+
- name: Test
36+
working-directory: ${{github.workspace}}
37+
run: python3.11 nob.py
38+
- name: Robot
39+
run: PYTHONPATH=.:robot robot -d logs robot/NobTestSuite.robot

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ a.out
55
gcm.cache/
66
.ycm_extra_conf.py
77
__pycache__/
8+
nobuild/
9+
venv/

.gitmodules

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "ext/nanobind"]
2+
path = ext/nanobind
3+
url = https://github.com/wjakob/nanobind

build_nb.sh

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/bin/sh -x
2+
3+
mkdir nobuild
4+
5+
PYTHON_INCLUDE=`pkg-config --cflags python3`
6+
7+
g++ nobnb.cpp -std=c++20 -fvisibility=hidden -DNDEBUG -DNB_COMPACT_ASSERTIONS $PYTHON_INCLUDE -fPIC -Iext/nanobind/include -Iext/nanobind/ext/robin_map/include -Os -c -o nobuild/nobnb.o
8+
9+
g++ ext/nanobind/src/nb_combined.cpp -std=c++20 -fvisibility=hidden -DNDEBUG -DNB_COMPACT_ASSERTIONS $PYTHON_INCLUDE -fPIC -Iext/nanobind/include -Iext/nanobind/ext/robin_map/include -O3 -fno-strict-aliasing -ffunction-sections -fdata-sections -c -o nobuild/libnanobind.o
10+
11+
g++ -shared -Wl,-s -Wl,--gc-sections nobuild/nobnb.o nobuild/libnanobind.o -o nobuild/nob.cpython-311-x86_64-linux-gnu.so

ext/nanobind

Submodule nanobind added at 12c3c79

nob.cpp

+42-14
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,46 @@
11
#define NOBUILD_IMPLEMENTATION
22
#include "./nob.h"
33

4-
#include <cassert>
4+
#include <array>
5+
#include <cstdlib>
56
#include <filesystem>
67
#include <queue>
78
#include <string_view>
89
#include <vector>
910

10-
#define CFLAGS "-Wall", "-Wextra", "-std=c2x", "-pedantic"
11-
#define CPPFLAGS "-Wall", "-Wextra", "-std=c++23", "-pedantic", "-Wconversion"
11+
#define CFLAGS "-std=c2x", "-Wall", "-Wextra", "-pedantic"
12+
#define CPPFLAGS "-std=c++23", "-Wall", "-Wconversion", "-Wextra", "-pedantic", "-fsanitize=address,pointer-overflow,signed-integer-overflow,undefined"
1213

1314
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
1415

16+
17+
#define MAKE_CMD(...) \
18+
({Cmd cmd = { \
19+
.line = cstr_array_make(__VA_ARGS__, NULL) \
20+
}; \
21+
Cstr cmd_to_show = cmd_show(cmd); \
22+
INFO("MAKE_CMD: %s", cmd_to_show); \
23+
std::free(reinterpret_cast<void*>( \
24+
const_cast<char*>(cmd_to_show))); \
25+
cmd;}) \
26+
27+
1528
namespace fs = std::filesystem;
1629

1730
using namespace std::string_literals; // for operator""s
1831
using namespace std::literals; // for operator""sv
1932

20-
void build_kattis_c_file(std::string_view filename) {
21-
Cstr path = PATH("kattis", filename.data());
22-
CMD("cc", CFLAGS, "-o", NOEXT(path), path);
33+
void build_kattis_c_file(std::string_view path) {
34+
Cstr noextpath = NOEXT(path.data());
35+
CMD("cc", CFLAGS, "-o", noextpath, path.data());
36+
std::free(reinterpret_cast<void*>(const_cast<char *>(noextpath))); // :-O
2337
}
2438

2539
void build_kattis_c_files() {
2640
for (auto const& entry : fs::directory_iterator("kattis"))
2741
if (fs::is_regular_file(entry.path())) {
28-
auto const filename = entry.path().filename().string();
29-
if (filename.ends_with(".c"))
30-
build_kattis_c_file(filename);
42+
const std::string& path = entry.path().string();
43+
if (path.ends_with(".c")) build_kattis_c_file(path);
3144
}
3245
}
3346

@@ -45,10 +58,21 @@ void build_custom_cpp_files() {
4558
}
4659
}
4760

61+
template<size_t N>
62+
void make_and_run_cmd(std::array<Cstr, N> strings)
63+
{
64+
Cmd cmd;
65+
cmd.line.count = strings.size();
66+
cmd.line.elems = strings.data();
67+
//TODO FIX leaks.
68+
INFO("make_and_run_cmd: %s", cmd_show(cmd));
69+
cmd_run_sync(cmd);
70+
}
71+
4872
void build_cpp_file(std::string_view filename)
4973
{
5074
Cstr path = PATH(filename.data());
51-
CMD("g++", CPPFLAGS, "-o", NOEXT(path), path);
75+
make_and_run_cmd(std::array{"g++", CPPFLAGS, "-o", NOEXT(path), path});
5276
}
5377

5478
void build_and_run_gtest_file(std::string_view filename)
@@ -58,10 +82,14 @@ void build_and_run_gtest_file(std::string_view filename)
5882
CMD(NOEXT(path));
5983
}
6084

61-
Pid build_gtest_file_async(std::string_view filename)
85+
Pid build_gtest_file_async(std::string_view path)
6286
{
63-
Cstr path = PATH(filename.data());
64-
return cmd_run_async(MAKE_CMD("g++", CPPFLAGS, "-o", NOEXT(path), path, "-lgtest"), NULL, NULL);
87+
Cstr noextpath = NOEXT(path.data());
88+
Cmd cmd = MAKE_CMD("g++", CPPFLAGS, "-o", noextpath, path.data(), "-lgtest");
89+
Pid pid = cmd_run_async(cmd, NULL, NULL);
90+
std::free(reinterpret_cast<void*>(const_cast<char**>(cmd.line.elems)));
91+
std::free(reinterpret_cast<void*>(const_cast<char *>(noextpath))); // :-O
92+
return pid;
6593
}
6694

6795
Pid run_gtest_file_async(std::string_view filename)
@@ -143,7 +171,7 @@ int main(int argc, char* argv[])
143171
{
144172
GO_REBUILD_URSELF(argc, argv);
145173

146-
//build_kattis_c_files();
174+
build_kattis_c_files();
147175
//build_custom_cpp_files();
148176
//build_directory_cpp_files("adventofcode");
149177
//build_codeforces_cpp_files();

nob.h

+6-9
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
#include <unistd.h>
3333
#include <dirent.h>
3434
#include <fcntl.h>
35-
#include <limits.h>
3635
#define PATH_SEP "/"
3736
typedef pid_t Pid;
3837
typedef int Fd;
@@ -107,17 +106,15 @@ typedef struct {
107106
Cmd cmd = { \
108107
.line = cstr_array_make(__VA_ARGS__, NULL) \
109108
}; \
110-
INFO("CMD: %s", cmd_show(cmd)); \
109+
Cstr cmd_to_show = cmd_show(cmd); \
110+
INFO("CMD: %s", cmd_to_show); \
111+
std::free(reinterpret_cast<void*>( \
112+
const_cast<char*>(cmd_to_show))); \
111113
cmd_run_sync(cmd); \
114+
std::free(reinterpret_cast<void*>( \
115+
const_cast<char**>(cmd.line.elems))); \
112116
} while (0)
113117

114-
#define MAKE_CMD(...) \
115-
({Cmd cmd = { \
116-
.line = cstr_array_make(__VA_ARGS__, NULL) \
117-
}; \
118-
INFO("MAKE_CMD: %s", cmd_show(cmd)); \
119-
cmd;}) \
120-
121118
typedef enum {
122119
CHAIN_TOKEN_END = 0,
123120
CHAIN_TOKEN_IN,

nob.py

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import nobuild.nob as nob
2+
3+
nob.make_and_run_cmd(["ls", "--color", "-l", "-t"])
4+
nob.make_and_run_cmd(["pwd"])

nobnb.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#include <utility>
2+
3+
#include <nanobind/nanobind.h>
4+
#include <nanobind/stl/array.h>
5+
6+
#include "nob.cpp"
7+
8+
namespace nb = nanobind;
9+
10+
NB_MODULE(nob, m) {
11+
nb::class_<Cmd>(m, "Cmd")
12+
.def(nb::init<>())
13+
.def_rw("line", &Cmd::line);
14+
15+
[&m]<std::size_t... Is>(std::index_sequence<Is...>) {
16+
(m.def("make_and_run_cmd", &make_and_run_cmd<Is + 1>), ...);
17+
}(std::make_index_sequence<19>{});
18+
}

robot/NobRobotLib.py

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import nobuild.nob as nob
2+
import os
3+
import time
4+
5+
class NobRobotLib:
6+
def __init__(self) -> None:
7+
pass
8+
9+
def build_executable(self):
10+
nob.make_and_run_cmd(["g++", "template.cc"])
11+
12+
def get_executable_time(self):
13+
return os.path.getmtime('a.out')
14+
15+
def get_current_time(self):
16+
return time.time()

robot/NobTestSuite.robot

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
*** Settings ***
2+
Documentation Basic nob test suite.
3+
Resource keywords.resource
4+
5+
*** Test Cases ***
6+
Test Case 1
7+
Build file
8+
Verify build

robot/keywords.resource

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
*** Settings ***
2+
Documentation
3+
Library NobRobotLib
4+
5+
*** Keywords ***
6+
Build file
7+
Build executable
8+
9+
Verify build
10+
${file_time}= Get Executable Time
11+
${time}= Get current time
12+
Should be true ${time}-${file_time} <= 1

0 commit comments

Comments
 (0)