Skip to content

Commit

Permalink
Introducing C Bindings (#75)
Browse files Browse the repository at this point in the history
Adds a new component (clib) for a library linkable to C

+ adds testing for C and python bindings
+ enhanced Doxygen documentation
+ fixes in the snapshot mechanism
  • Loading branch information
JBenda authored Jan 11, 2024
1 parent f206701 commit f245cf6
Show file tree
Hide file tree
Showing 64 changed files with 2,331 additions and 825 deletions.
35 changes: 22 additions & 13 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,19 @@ jobs:
name: MacOSX
inklecate_url: https://github.com/inkle/ink/releases/download/v1.1.1/inklecate_mac.zip
proof: false
unreal: false
- os: windows-latest
artifact: win64
name: Windows x64
inklecate_url: https://github.com/inkle/ink/releases/download/v1.1.1/inklecate_windows.zip
proof: false
unreal: false
- os: "ubuntu-20.04"
artifact: linux
name: Linux x64
inklecate_url: https://github.com/inkle/ink/releases/download/v1.1.1/inklecate_linux.zip
proof: true
unreal: true

steps:

Expand Down Expand Up @@ -74,7 +77,7 @@ jobs:
- name: Configure CMake
shell: bash
working-directory: ${{github.workspace}}/build
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DINKCPP_PY=OFF
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DINKCPP_PY=OFF -DINKCPP_C=ON

# Build using CMake and OS toolkit
- name: Build
Expand All @@ -89,40 +92,46 @@ jobs:
run: ctest . -C $BUILD_TYPE -V

# Copy all build artifacts to the bin directory
- name: Install CL
- name: Install Cl
working-directory: ${{github.workspace}}/build
shell: bash
run: cmake --install . --config $BUILD_TYPE --prefix comp_cl --component cl

# Upload bin directory as artifact
- name: Upload Binary Artifact
- name: Upload Cl
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.artifact }}-cl
path: build/comp_cl/

- name: Install LIB
- name: Install Lib
working-directory: ${{github.workspace}}/build
shell: bash
run: cmake --install . --config $BUILD_TYPE --prefix comp_lib --component lib

# Upload bin directory as artifact
- name: Upload Binary Artifact
- name: Upload Lib
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.artifact }}-lib
path: build/comp_lib/

- name: Install CLib
working-directory: ${{github.workspace}}/build
shell: bash
run: cmake --install . --config $BUILD_TYPE --prefix comp_clib --component clib
- name: Upload Clib
uses: actions/upload-artifact@v3
with:
name: ${{matrix.artifact}}-clib
path: build/comp_clib

- name: Install UE
if: ${{ matrix.unreal }}
working-directory: ${{github.workspace}}/build
shell: bash
run: cmake --install . --config $BUILD_TYPE --prefix comp_unreal --component unreal

# Upload bin directory as artifact
- name: Upload Binary Artifact
- name: Upload UE
if: ${{ matrix.unreal }}
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.artifact }}-unreal
name: unreal
path: build/comp_unreal/

# Make sure Inkproof has everything it needs to run our executable
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ jobs:
- name: Download artifacts
uses: marcofaggian/action-download-multiple-artifacts@v3.0.8
with:
names: linux-cl linux-lib linux-unreal macos-cl macos-lib macos-unreal win64-cl win64-lib win64-unreal python-package-distribution
paths: linux-cl linux-lib linux-unreal macos-cl macos-lib macos-unreal win64-cl win64-lib win64-unreal dist
names: linux-cl linux-lib linux-clib unreal macos-cl macos-lib macos-clib win64-cl win64-lib win64-clib python-package-distribution
paths: linux-cl linux-lib linux-clib unreal macos-cl macos-lib macos-cliswin64-cl win64-lib win64-clib dist
workflow: build.yml
branch: master
- name: Zip
run: |
for f in linux-cl linux-lib linux-unreal macos-cl macos-lib macos-unreal win64-cl win64-lib win64-unreal; do zip -r $f $f; done
for f in linux-cl linux-lib linux-clib unreal macos-cl macos-lib macos-clib win64-cl win64-lib win64-clib; do zip -r $f $f; done
- name: List
run: tree
- name: Publish to PyPI
Expand All @@ -43,5 +43,5 @@ jobs:
--repo="$GITHUB_REPOSITORY" \
--title="${GITHUB_REPOSITORY#*/} ${tag#v}" \
--generate-notes \
"$tag" "linux-cl.zip" "linux-lib.zip" "linux-unreal.zip" "macos-cl.zip" "macos-lib.zip" "macos-unreal.zip" "win64-cl.zip" "win64-lib.zip" "win64-unreal.zip"
"$tag" "linux-cl.zip" "linux-lib.zip" "linux-clib.zip" "unreal.zip" "macos-cl.zip" "macos-lib.zip" "macos-clib.zip" "win64-cl.zip" "win64-lib.zip" "win64-clib.zip"
15 changes: 9 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.16)
enable_testing()

# Project setup
project(inkcpp VERSION 0.1.1)
project(inkcpp VERSION 0.1.2)
SET(CMAKE_CXX_STANDARD 20)
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
SET(CMAKE_INSTALL_LIBRARY_DIR lib)
Expand All @@ -13,6 +13,7 @@ SET(CMAKE_INSTALL_INCLUDE_DIR include)
# Add subdirectories
set(INKCPP_PY OFF CACHE BOOL "Build python bindings")
set(WHEEL_BUILD OFF CACHE BOOL "Set for build wheel python lib (do not forgett INKCPP_PY")
set(INKCPP_C OFF CACHE BOOL "Build c library")

if (INKCPP_PY)
add_compile_options(-fPIC)
Expand All @@ -21,15 +22,17 @@ endif(INKCPP_PY)
add_subdirectory(shared)
add_subdirectory(inkcpp)
add_subdirectory(inkcpp_compiler)
if (INKCPP_C)
add_subdirectory(inkcpp_c)
endif(INKCPP_C)
if (NOT WHEEL_BUILD)
add_subdirectory(inkcpp_cl)
add_subdirectory(inkcpp_test)
add_subdirectory(unreal)
add_subdirectory(inkcpp_cl)
add_subdirectory(inkcpp_test)
add_subdirectory(unreal)
endif(NOT WHEEL_BUILD)



install(TARGETS inkcpp inkcpp_compiler inkcpp_shared
install(TARGETS inkcpp inkcpp_shared inkcpp_compiler
EXPORT inkcppTarget
ARCHIVE DESTINATION "lib/ink"
COMPONENT lib EXCLUDE_FROM_ALL
Expand Down
Binary file modified Documentation/cmake_example.zip
Binary file not shown.
8 changes: 6 additions & 2 deletions Documentation/cmake_example/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ project(main)

find_package(inkcpp CONFIG REQUIRED)

add_executable(main main.cpp)
set_property(TARGET main PROPERTY CXX_STANDARD 17)
# for CXX builds
add_executable(main_cpp main.cpp)
target_link_libraries(main inkcpp inkcpp_compiler)

# for C builds
# add_executable(main_c main.c)
# target_link_libraries(main inkcpp_c)
38 changes: 38 additions & 0 deletions Documentation/cmake_example/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>

#include <ink/c/inkcpp.h> // if <os>-lib.zip was used for the installation

// #include <ink/inkcpp.h> // if <os>-clib.zip was used for the installation

InkValue ink_add(int argc, const InkValue argv[])
{
assert(argc == 2);
assert(argv[0].type == ValueTypeInt32 && argv[1].type == ValueTypeInt32);
return (InkValue){.type = ValueTypeInt32, .int32_v = argv[0].int32_v + argv[1].int32_v};
}

int main()
{
ink_compile_json("test.ink.json", "test.bin", NULL);
HInkStory* story = ink_story_from_file("test.bin");
HInkRunner* runner = ink_story_new_runner(story, NULL);

ink_runner_bind(runner, "my_ink_function", ink_add, 1);

while (1) {
while (ink_runner_can_continue(runner)) {
printf("%s", ink_runner_get_line(runner));
}
if (ink_runner_num_choices(runner) == 0)
break;
for (int i = 0; i < ink_runner_num_choices(runner); ++i) {
printf("%i. %s\n", i, ink_choice_text(ink_runner_get_choice(runner, i)));
}

int id;
scanf("%i", &id);
ink_runner_choose(runner, id);
}
}
1 change: 1 addition & 0 deletions Documentation/cmake_example/test.ink.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"inkVersion":21,"root":[["^Hello world!","\n",["ev",{"^->":"0.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":"0.c-0","flg":18},{"s":["^Hello back!",{"->":"$r","var":true},null]}],["ev",{"^->":"0.3.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":"0.c-1","flg":18},{"s":["^Bye",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":"0.2.s"},[{"#n":"$r2"}],"\n","^Nice to hear from you!","\n",{"->":"0.g-0"},{"#f":5}],"c-1":["ev",{"^->":"0.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":"0.3.s"},[{"#n":"$r2"}],"\n","^BTW 3 + 5 = ","ev",3,5,{"x()":"my_ink_function","exArgs":2},"out","/ev","\n","end",{"->":"0.g-0"},{"#f":5}],"g-0":["done",null]}],"done",null],"listDefs":{}}
5 changes: 3 additions & 2 deletions Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -946,7 +946,8 @@ WARN_LOGFILE =
INPUT = inkcpp/include \
shared/public \
inkcpp_compiler/include \
unreal/inkcpp/Source/inkcpp/Public/
unreal/inkcpp/Source/inkcpp/Public \
inkcpp_c/include

# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
Expand Down Expand Up @@ -1686,7 +1687,7 @@ DISABLE_INDEX = NO
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.

GENERATE_TREEVIEW = NO
GENERATE_TREEVIEW = YES

# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the
# FULL_SIDEBAR option determines if the side bar is limited to only the treeview
Expand Down
11 changes: 9 additions & 2 deletions inkcpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,23 @@ list(APPEND COLLECTION_SOURCES
collections/restorable.h
collections/restorable.cpp
)
FILE(GLOB PUBLIC_HEADERS "include/*")

source_group(Collections REGULAR_EXPRESSION collections/.*)
add_library(inkcpp ${SOURCES} ${COLLECTION_SOURCES})
add_library(inkcpp_o OBJECT ${SOURCES} ${COLLECTION_SOURCES})
target_include_directories(inkcpp_o PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
add_library(inkcpp $<TARGET_OBJECTS:inkcpp_o>)
target_include_directories(inkcpp PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
FILE(GLOB PUBLIC_HEADERS "include/*")
set_target_properties(inkcpp PROPERTIES PUBLIC_HEADER "${PUBLIC_HEADERS}")

# Make sure the include directory is included
target_link_libraries(inkcpp_o PRIVATE inkcpp_shared)
target_link_libraries(inkcpp PRIVATE inkcpp_shared)
# Make sure this project and all dependencies use the C++17 standard
target_compile_features(inkcpp PUBLIC cxx_std_17)
Expand Down
72 changes: 40 additions & 32 deletions inkcpp/array.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,37 +279,6 @@ class basic_restorable_array : public snapshot_interface
const T _null;
};

template<typename T>
inline size_t basic_restorable_array<T>::snap(unsigned char* data, const snapper& snapper) const
{
unsigned char* ptr = data;
bool should_write = data != nullptr;
ptr = snap_write(ptr, _saved, should_write);
ptr = snap_write(ptr, _capacity, should_write);
ptr = snap_write(ptr, _null, should_write);
for (size_t i = 0; i < _capacity; ++i) {
ptr = snap_write(ptr, _array[i], should_write);
ptr = snap_write(ptr, _temp[i], should_write);
}
return ptr - data;
}

template<typename T>
inline const unsigned char*
basic_restorable_array<T>::snap_load(const unsigned char* data, const loader& loader)
{
auto ptr = data;
ptr = snap_read(ptr, _saved);
ptr = snap_read(ptr, _capacity);
T null;
ptr = snap_read(ptr, null);
inkAssert(null == _null, "null value is different to snapshot!");
for (size_t i = 0; i < _capacity; ++i) {
ptr = snap_read(ptr, _array[i]);
ptr = snap_read(ptr, _temp[i]);
}
return ptr;
}

template<typename T>
inline void basic_restorable_array<T>::set(size_t index, const T& value)
Expand Down Expand Up @@ -440,7 +409,7 @@ class allocated_restorable_array final : public basic_restorable_array<T>
}
delete[] _buffer;
}
for (size_t i = base::capacity(); i < new_capacity; ++i) {
for (size_t i = base::capacity(); i < new_capacity / 2; ++i) {
new_buffer[i] = _initialValue;
new_buffer[i + base::capacity()] = _nullValue;
}
Expand All @@ -462,4 +431,43 @@ class allocated_restorable_array final : public basic_restorable_array<T>
T _nullValue;
T* _buffer;
};

template<typename T>
inline size_t basic_restorable_array<T>::snap(unsigned char* data, const snapper& snapper) const
{
unsigned char* ptr = data;
bool should_write = data != nullptr;
ptr = snap_write(ptr, _saved, should_write);
ptr = snap_write(ptr, _capacity, should_write);
ptr = snap_write(ptr, _null, should_write);
for (size_t i = 0; i < _capacity; ++i) {
ptr = snap_write(ptr, _array[i], should_write);
ptr = snap_write(ptr, _temp[i], should_write);
}
return ptr - data;
}

template<typename T>
inline const unsigned char*
basic_restorable_array<T>::snap_load(const unsigned char* data, const loader& loader)
{
auto ptr = data;
ptr = snap_read(ptr, _saved);
decltype(_capacity) capacity;
ptr = snap_read(ptr, capacity);
if (buffer() == nullptr) {
static_cast<allocated_restorable_array<T>&>(*this).resize(capacity);
}
inkAssert(
_capacity >= capacity, "New config does not allow for necessary size used by this snapshot!"
);
T null;
ptr = snap_read(ptr, null);
inkAssert(null == _null, "null value is different to snapshot!");
for (size_t i = 0; i < _capacity; ++i) {
ptr = snap_read(ptr, _array[i]);
ptr = snap_read(ptr, _temp[i]);
}
return ptr;
}
} // namespace ink::runtime::internal
Loading

0 comments on commit f245cf6

Please sign in to comment.