Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cmake support #27

Merged
merged 2 commits into from
Feb 5, 2025
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
41 changes: 41 additions & 0 deletions .github/workflows/cmake.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: CMake build and test

on:
push:
branches:
- master
paths-ignore:
- '*.md'
- 'docs/**'
pull_request:
types: [ opened, synchronize ]
paths-ignore:
- '*.md'
- 'docs/**'
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build:
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

# The library targets C89, so we force C89 compatibility in CI.
# We do not force it by default in CMake because that can cause
# build errors if the stdlib headers require a newer C standard.
- name: Build
run: |
cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_STANDARD=90 -DCMAKE_C_EXTENSIONS=OFF -DCMAKE_C_STANDARD_REQUIRED=ON
cmake --build build -j $(getconf _NPROCESSORS_ONLN)

- name: Run tests
run: ctest --test-dir build --output-on-failure -j $(getconf _NPROCESSORS_ONLN)
191 changes: 191 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
cmake_minimum_required(VERSION 3.16)

project(SheenBidi VERSION 2.8 LANGUAGES C CXX)

include(CTest)

set(ASAN $<CONFIG:Debug> CACHE STRING "Enable address sanitizer" )
set(UBSAN $<CONFIG:Debug> CACHE STRING "Enable undefined behaviour sanitizer")

# C++ is only used for testing tools.
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED OFF)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # for clang-tidy

function(add_sanitizers TARGET)
if(NOT MSVC)
target_compile_options(${TARGET} PUBLIC $<$<BOOL:${ASAN}>:-fsanitize=address;-fsanitize-recover=address>)
target_link_libraries(${TARGET} PUBLIC $<$<BOOL:${ASAN}>:-fsanitize=address;-fsanitize-recover=address>)
target_compile_options(${TARGET} PUBLIC $<$<BOOL:${UBSAN}>:-fsanitize=undefined>)
target_link_libraries(${TARGET} PUBLIC $<$<BOOL:${UBSAN}>:-fsanitize=undefined>)
endif()
endfunction()

# https://learn.microsoft.com/en-us/cpp/build/reference/utf-8-set-source-and-executable-character-sets-to-utf-8?view=msvc-170
# https://learn.microsoft.com/en-us/cpp/build/reference/zc-cplusplus?view=msvc-170
add_compile_options("$<$<COMPILE_LANG_AND_ID:C,MSVC>:/utf-8>")
add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,MSVC>:/utf-8;/Zc:__cplusplus>")

set(_public_headers
Headers/SBAlgorithm.h
Headers/SBBase.h
Headers/SBBidiType.h
Headers/SBCodepoint.h
Headers/SBCodepointSequence.h
Headers/SBGeneralCategory.h
Headers/SBLine.h
Headers/SBMirrorLocator.h
Headers/SBParagraph.h
Headers/SBRun.h
Headers/SBScript.h
Headers/SBScriptLocator.h
Headers/SheenBidi.h
)
set(_non_unity_sources
Source/BidiChain.c
Source/BidiTypeLookup.c
Source/BracketQueue.c
Source/GeneralCategoryLookup.c
Source/IsolatingRun.c
Source/LevelRun.c
Source/PairingLookup.c
Source/RunQueue.c
Source/SBAlgorithm.c
Source/SBBase.c
Source/SBCodepointSequence.c
Source/SBLine.c
Source/SBLog.c
Source/SBMirrorLocator.c
Source/SBParagraph.c
Source/SBScriptLocator.c
Source/ScriptLookup.c
Source/ScriptStack.c
Source/StatusStack.c
)
set(_is_unity $<NOT:$<CONFIG:Debug>>)
add_library(
sheenbidi
$<IF:${_is_unity},Source/SheenBidi.c,${_non_unity_sources}>
)
target_include_directories(sheenbidi PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/Headers>
$<INSTALL_INTERFACE:include/SheenBidi>
)
target_include_directories(sheenbidi PRIVATE Source)
set_target_properties(sheenbidi PROPERTIES PUBLIC_HEADER "${_public_headers}")
target_compile_definitions(sheenbidi PUBLIC $<${_is_unity}:SB_CONFIG_UNITY>)
add_library(SheenBidi::sheenbidi ALIAS sheenbidi)
add_sanitizers(sheenbidi)

add_library(
parser
Tools/Parser/BidiBrackets.cpp
Tools/Parser/BidiCharacterTest.cpp
Tools/Parser/BidiMirroring.cpp
Tools/Parser/BidiTest.cpp
Tools/Parser/DerivedBidiClass.cpp
Tools/Parser/PropertyValueAliases.cpp
Tools/Parser/Scripts.cpp
Tools/Parser/UnicodeData.cpp
Tools/Parser/UnicodeVersion.cpp
)
target_include_directories(parser PUBLIC Tools)
target_link_libraries(parser PUBLIC sheenbidi)
add_sanitizers(parser)

add_executable(
generator
Tools/Generator/main.cpp
Tools/Generator/BidiTypeLookupGenerator.cpp
Tools/Generator/GeneralCategoryLookupGenerator.cpp
Tools/Generator/PairingLookupGenerator.cpp
Tools/Generator/ScriptLookupGenerator.cpp
Tools/Generator/Utilities/ArrayBuilder.cpp
Tools/Generator/Utilities/BidiClassDetector.cpp
Tools/Generator/Utilities/Converter.cpp
Tools/Generator/Utilities/FileBuilder.cpp
Tools/Generator/Utilities/GeneralCategoryDetector.cpp
Tools/Generator/Utilities/Math.cpp
Tools/Generator/Utilities/ScriptDetector.cpp
Tools/Generator/Utilities/StreamBuilder.cpp
Tools/Generator/Utilities/TextBuilder.cpp
)
target_include_directories(generator PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
target_link_libraries(generator PUBLIC parser sheenbidi)
add_sanitizers(generator)

if(BUILD_TESTING)
add_executable(
tester
Tools/Tester/main.cpp
Tools/Tester/Configuration.cpp
Tools/Tester/MirrorLookupTester.cpp
Tools/Tester/ScriptLookupTester.cpp
Tools/Tester/AlgorithmTester.cpp
Tools/Tester/ScriptLocatorTester.cpp
Tools/Tester/BidiTypeLookupTester.cpp
Tools/Tester/CodepointSequenceTester.cpp
Tools/Tester/GeneralCategoryLookupTester.cpp
Tools/Tester/BracketLookupTester.cpp
Tools/Tester/Utilities/Convert.cpp
Tools/Tester/Utilities/Unicode.cpp
)
target_include_directories(tester PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}" Tools)
target_link_libraries(tester PRIVATE parser sheenbidi)
add_sanitizers(tester)

add_test(
NAME tests
COMMAND tester ${CMAKE_CURRENT_SOURCE_DIR}/Tools/Unicode
)
set_tests_properties(tests PROPERTIES
TIMEOUT 180
FAIL_REGULAR_EXPRESSION "[1-9][0-9]* error"
)
endif()

install(
TARGETS sheenbidi
EXPORT SheenBidiTargets
PUBLIC_HEADER
CONFIGURATIONS Release
DESTINATION include/SheenBidi
)

if(NOT DEFINED LIB_INSTALL_DIR)
set(LIB_INSTALL_DIR lib)
endif()
set(ConfigPackageLocation "${LIB_INSTALL_DIR}/cmake/SheenBidi")

include(CMakePackageConfigHelpers)
configure_package_config_file(SheenBidi.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/SheenBidi/SheenBidiConfig.cmake"
INSTALL_DESTINATION ${ConfigPackageLocation})
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/SheenBidi/SheenBidiConfigVersion.cmake"
VERSION ${SheenBidi_VERSION}
COMPATIBILITY AnyNewerVersion
)

export(EXPORT SheenBidiTargets
FILE "${CMAKE_CURRENT_BINARY_DIR}/SheenBidi/SheenBidiTargets.cmake"
NAMESPACE SheenBidi::
)

install(EXPORT SheenBidiTargets
FILE
SheenBidiTargets.cmake
NAMESPACE
SheenBidi::
DESTINATION
${ConfigPackageLocation}
)
install(
FILES
"${CMAKE_CURRENT_BINARY_DIR}/SheenBidi/SheenBidiConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/SheenBidi/SheenBidiConfigVersion.cmake"
DESTINATION
${ConfigPackageLocation}
)
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,32 @@ The configuration options are available in `Headers/SBConfig.h`.
## Compiling
SheenBidi can be compiled with any C compiler. The best way for compiling is to add all the files in an IDE and hit build. The only thing to consider however is that if ```SB_CONFIG_UNITY``` is enabled then only ```Source/SheenBidi.c``` should be compiled.

### CMake

SheenBidi can also be compiled and installed with CMake:

```bash
cmake -S. -Bbuild-rel -DCMAKE_BUILD_TYPE=Release
cmake --build build-rel -j $(getconf _NPROCESSORS_ONLN)
sudo cmake --install build-rel
```

The installed package can be found in other CMake projects via
`find_package(SheenBidi)`.

SheenBidi provides a single target, `SheenBidi::sheenbidi`.
SheenBidi can also be used via `FetchContent`.

### Testing with CMake

If you're working on SheenBidi itself, you can build and run the tests with:

```bash
cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Debug
cmake --build build -j $(getconf _NPROCESSORS_ONLN)
ctest --test-dir build --output-on-failure -j $(getconf _NPROCESSORS_ONLN)
```

## Example
Here is a simple example written in C11.

Expand Down
5 changes: 5 additions & 0 deletions SheenBidi.cmake.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@PACKAGE_INIT@

check_required_components(SheenBidi)

include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]")
8 changes: 6 additions & 2 deletions Tools/Generator/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,12 @@ using namespace SheenBidi::Generator;

int main(int argc, const char * argv[])
{
const string in = "/path/to/input";
const string out = "/path/to/output";
if (argc > 3) {
cerr << "Usage: " << argv[0] << " [input_dir] [output_dir]" << endl;
return 64;
}
const string in = argc >= 2 ? argv[1] : "Tools/Unicode";
const string out = argc == 3 ? argv[2] : "Source";

UnicodeData unicodeData(in);
BidiMirroring bidiMirroring(in);
Expand Down