Skip to content

Commit e72d827

Browse files
authored
Add GitHub Actions (ridiculousfish#122)
* GitHub Action: AVR build & unit test * Only run benchmark test on Release builds. * Switch to GitHub actions * Add manual run * Use workflow_call instead of workflow_run workflow_run will "only trigger a workflow run if the workflow file is on the default branch." * Use the ClangCL toolset on Windows+CLang * Lookup the C compiler & force build tests on * Simplify matrix, force tests on & clang fuzzing * Turn off clang fuzzers - compilation errors * Split Windows builds into separate jobs There is quite a big difference in the compiler toolchains. * Use marketplace cmake action * Windows: need to use MSVC command prompt So compilers are in the path. * Use MSVC compile options for clang-cl * Windows: specify generators * clang-cl: disable __umulh/__mulh intrinsics prior to VS2022 * Sanitize: use target_compile_options & target_link_options * Build on multiple ubuntu versions * Speed up canary build * Launch AVR build only on canary build success * Reinstate appveyor support * Update readme Build Status badge
1 parent e4d0295 commit e72d827

14 files changed

+425
-81
lines changed

.github/workflows/avr_build_test.yml

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: AVR Build & Unit Tests
2+
3+
on:
4+
# This job takes a long time to run, so only run it when the canary build passes
5+
# Ideally we'd use the workflow_run trigger and have GitHub launch this action, but the docs state:
6+
# This event will only trigger a workflow run if the workflow file is on the default branch.
7+
# ...which leads to some interesting behaviors
8+
workflow_call:
9+
# Allows you to run this workflow manually from the Actions tab
10+
workflow_dispatch:
11+
12+
jobs:
13+
AVRSimulator-Unit-Test:
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- uses: actions/checkout@v4
18+
19+
- name: Set up Python
20+
uses: actions/setup-python@v5
21+
with:
22+
python-version: '3.10'
23+
24+
- name: Install PlatformIO
25+
working-directory: ./test/avr
26+
run: |
27+
python -m pip install --upgrade pip
28+
pip install --upgrade platformio
29+
pip install wheel
30+
platformio upgrade
31+
platformio pkg update
32+
33+
- name: Build All Environments
34+
shell: pwsh
35+
working-directory: ./test/avr
36+
run: Get-Content -Path .\platformio.ini | Where-Object { $_.StartsWith("[env:") } | ForEach-Object { & pio run -e $_.SubString(5, $_.Length-6) }
37+
38+
- name: Run Simulator Unit Tests
39+
working-directory: ./test/avr
40+
run: platformio test -v -e megaatmega2560_sim_unittest

.github/workflows/canary_build.yml

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
name: Canary Build and Test
2+
3+
on:
4+
push:
5+
pull_request:
6+
# Allows you to run this workflow manually from the Actions tab
7+
workflow_dispatch:
8+
9+
env:
10+
build_type: Release
11+
cpp_compiler: g++
12+
output_folder: ${{github.workspace}}/build/
13+
14+
jobs:
15+
Canary-Build:
16+
runs-on: ubuntu-latest
17+
18+
steps:
19+
- uses: actions/checkout@v4
20+
21+
- name: Configure CMake & Build
22+
env:
23+
# Map from C++ compiler to equivalent C compiler
24+
g++: gcc
25+
clang++: clang
26+
uses: threeal/[email protected]
27+
with:
28+
build-dir: ${{ env.output_folder }}
29+
c-compiler: ${{ env[env.cpp_compiler] }}
30+
cxx-compiler: ${{ env.cpp_compiler }}
31+
build-args: -t tester
32+
options: |
33+
LIBDIVIDE_BUILD_TESTS=ON
34+
CMAKE_BUILD_TYPE=${{ env.build_type }}
35+
36+
- name: Test
37+
working-directory: ${{env.output_folder}}
38+
run: ctest --build-config ${{env.build_type}} --verbose --tests-regex tester
39+
40+
# Kick off the full build if everything above succeeded
41+
Full-Build:
42+
needs: Canary-Build
43+
uses: ./.github/workflows/full_build.yml
44+
45+
# Kick off the full build if everything above succeeded
46+
AVR-Build:
47+
needs: Canary-Build
48+
uses: ./.github/workflows/avr_build_test.yml

.github/workflows/full_build.yml

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
name: Full Build and Test
2+
3+
on:
4+
# This job takes a long time to run, so only run it when the canary build passes
5+
# Ideally we'd use the workflow_run trigger and have GitHub launch this action, but the docs state:
6+
# This event will only trigger a workflow run if the workflow file is on the default branch.
7+
# ...which leads to some interesting behaviors
8+
workflow_call:
9+
# Allows you to run this workflow manually from the Actions tab
10+
workflow_dispatch:
11+
12+
jobs:
13+
Full-Build-Ubuntu:
14+
runs-on: ${{ matrix.os }}
15+
16+
strategy:
17+
# We want to test all matrix combinations regardless of failure
18+
fail-fast: false
19+
20+
matrix:
21+
os:
22+
- ubuntu-24.04
23+
- ubuntu-20.04
24+
build_type:
25+
- Release
26+
- Sanitize
27+
cpp_compiler:
28+
- g++
29+
- clang++
30+
31+
env:
32+
output_folder: ${{github.workspace}}/build/
33+
34+
steps:
35+
- uses: actions/checkout@v4
36+
37+
- name: Configure CMake & Build
38+
env:
39+
# Map from C++ compiler to equivalent C compiler
40+
g++: gcc
41+
clang++: clang
42+
uses: threeal/[email protected]
43+
with:
44+
build-dir: ${{ env.output_folder }}
45+
c-compiler: ${{ env[matrix.cpp_compiler] }}
46+
cxx-compiler: ${{ matrix.cpp_compiler }}
47+
options: |
48+
LIBDIVIDE_BUILD_TESTS=ON
49+
CMAKE_BUILD_TYPE=${{ matrix.build_type }}
50+
build-args: --config ${{ matrix.build_type }}
51+
52+
- name: Test
53+
working-directory: ${{ env.output_folder }}
54+
# Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator).
55+
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
56+
run: ctest --build-config ${{ matrix.build_type }} --verbose
57+
58+
Full-Build-Windows:
59+
runs-on: ${{ matrix.os }}
60+
61+
strategy:
62+
# We want to test all matrix combinations regardless of failure
63+
fail-fast: false
64+
# This makes development easier
65+
# max-parallel: 0
66+
matrix:
67+
os:
68+
- windows-2022
69+
- windows-2019
70+
build_type:
71+
- Release
72+
- Sanitize
73+
cpp_compiler:
74+
- clang-cl.exe
75+
- cl.exe
76+
include:
77+
# Set generator per os
78+
# Note: These *expand* the existing matrix configurations, it doesn't create new matrix configurations
79+
# See https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategymatrixinclude
80+
- os: windows-2022
81+
generator: Visual Studio 17 2022
82+
- os: windows-2019
83+
generator: Visual Studio 16 2019
84+
# clang-cl requires the toolset flag be set correctly
85+
- cpp_compiler: clang-cl.exe
86+
toolset: ClangCL
87+
exclude:
88+
# MSVC Clang toolchain fails sanitization
89+
- cpp_compiler: clang-cl.exe
90+
build_type: Sanitize
91+
92+
env:
93+
output_folder: ${{github.workspace}}/build/
94+
95+
steps:
96+
- uses: actions/checkout@v4
97+
- uses: ilammy/msvc-dev-cmd@v1
98+
99+
- name: Configure CMake & Build
100+
env:
101+
# Map from C++ compiler to equivalent C compiler
102+
cl.exe: cl.exe
103+
clang-cl.exe: clang-cl.exe
104+
toolset: ${{ matrix.toolset && format('-T {0}', matrix.toolset) || ''}}
105+
uses: threeal/[email protected]
106+
with:
107+
build-dir: ${{ env.output_folder }}
108+
c-compiler: ${{ env[matrix.cpp_compiler] }}
109+
cxx-compiler: ${{ matrix.cpp_compiler }}
110+
generator: ${{ matrix.generator }}
111+
args: ${{ env.toolset }}
112+
options: |
113+
LIBDIVIDE_BUILD_TESTS=ON
114+
CMAKE_BUILD_TYPE=${{ matrix.build_type }}
115+
build-args: --config ${{ matrix.build_type }}
116+
117+
- name: Test
118+
working-directory: ${{ env.output_folder }}
119+
# Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator).
120+
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
121+
run: ctest --build-config ${{ matrix.build_type }} --verbose

CMakeLists.txt

+28-11
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,23 @@ include(CheckCXXSourceRuns)
99
include(GNUInstallDirs)
1010
include(CMakePackageConfigHelpers)
1111
include(CMakePushCheckState)
12-
include(CMakeSanitize)
1312

1413
# Compile options ################################################
1514

1615
# Maximum warnings level & warnings as error
17-
add_compile_options(
18-
"$<$<CXX_COMPILER_ID:MSVC>:/W4;/WX>"
19-
"$<$<CXX_COMPILER_ID:GNU>:-Wall;-Wextra;-pedantic;-Werror>"
20-
"$<$<CXX_COMPILER_ID:Clang>:-Wall;-Wextra;-pedantic;-Werror>"
21-
"$<$<CXX_COMPILER_ID:AppleClang>:-Wall;-Wextra;-pedantic;-Werror>"
22-
)
16+
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
17+
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC") # clang-cl
18+
add_compile_options("/W4;/WX;")
19+
else() # clang native
20+
add_compile_options("-Wall;-Wextra;-pedantic;-Werror")
21+
endif()
22+
else()
23+
add_compile_options(
24+
"$<$<CXX_COMPILER_ID:MSVC>:/W4;/WX>"
25+
"$<$<CXX_COMPILER_ID:GNU>:-Wall;-Wextra;-pedantic;-Werror>"
26+
"$<$<CXX_COMPILER_ID:AppleClang>:-Wall;-Wextra;-pedantic;-Werror>"
27+
)
28+
endif()
2329

2430
# Build options ################################################
2531

@@ -232,6 +238,8 @@ endif()
232238
add_library(libdivide INTERFACE)
233239
add_library(libdivide::libdivide ALIAS libdivide)
234240

241+
include(CMakeSanitize)
242+
235243
target_compile_features(libdivide INTERFACE cxx_alias_templates)
236244

237245
target_include_directories(libdivide INTERFACE
@@ -303,13 +311,22 @@ endif()
303311
if (LIBDIVIDE_BUILD_TESTS)
304312
include(CTest)
305313
enable_testing()
306-
add_test(tester tester)
307-
add_test(benchmark_branchfree benchmark_branchfree)
308314

315+
add_test(tester tester)
309316
# cmake won't actually build the tests before it tries to run them
310317
add_test(build_tester "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target tester)
311-
add_test(build_benchmark_branchfree "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target benchmark_branchfree)
312-
set_tests_properties(tester benchmark_branchfree PROPERTIES DEPENDS "build_tester;build_benchmark_branchfree")
318+
set_tests_properties(tester PROPERTIES DEPENDS "build_tester")
319+
320+
add_test(test_c99 test_c99)
321+
add_test(build_test_c99 "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target test_c99)
322+
set_tests_properties(test_c99 PROPERTIES DEPENDS "build_test_c99")
323+
324+
# Only benchmark in release builds.
325+
if("${BUILD_TYPE}" MATCHES RELEASE)
326+
add_test(benchmark_branchfree benchmark_branchfree)
327+
add_test(build_benchmark_branchfree "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target benchmark_branchfree)
328+
set_tests_properties(benchmark_branchfree PROPERTIES DEPENDS "build_benchmark_branchfree")
329+
endif()
313330
endif()
314331

315332
# Build the fuzzers (requires clang) ###########################

CMakeSanitize

+16-11
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,6 @@ if(CMAKE_CONFIGURATION_TYPES)
1212
FORCE)
1313
endif()
1414

15-
if (CMAKE_C_COMPILER_ID STREQUAL "MSVC")
16-
set(COMPILER_FLAGS "/fsanitize=address /MTd")
17-
set(LINKER_FLAGS "/INCREMENTAL:NO")
18-
elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
19-
set(COMPILER_FLAGS "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer -U_DLL -U_MT -DDEBUG -O1 -g")
20-
set(LINKER_FLAGS "-fsanitize=address")
21-
elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU")
22-
set(COMPILER_FLAGS "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer -DDEBUG -O1 -g")
23-
set(LINKER_FLAGS "-fsanitize=address -fsanitize=undefined")
24-
endif()
25-
2615
set("CMAKE_CXX_FLAGS_${BUILD_NAME_U}" "${CMAKE_CXX_FLAGS_${BASE_BUILD_NAME_U}} ${COMPILER_FLAGS}" CACHE STRING
2716
"Flags used by the C++ compiler during ${BUILD_NAME} builds."
2817
FORCE)
@@ -46,3 +35,19 @@ mark_as_advanced(
4635
set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING
4736
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel ${BUILD_NAME}."
4837
FORCE)
38+
39+
if (CMAKE_C_COMPILER_ID STREQUAL "MSVC")
40+
target_compile_options(libdivide INTERFACE "$<$<CONFIG:${BUILD_NAME}>:/fsanitize=address;/MTd>")
41+
target_link_options(libdivide INTERFACE "$<$<CONFIG:${BUILD_NAME}>:/INCREMENTAL:NO>")
42+
elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
43+
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC") # clang-cl
44+
target_compile_options(libdivide INTERFACE "$<$<CONFIG:${BUILD_NAME}>:/fsanitize=address>")
45+
target_link_libraries(libdivide INTERFACE "$<$<CONFIG:${BUILD_NAME}>:clang_rt.asan_dynamic-x86_64.lib;clang_rt.asan_dynamic_runtime_thunk-x86_64.lib>")
46+
else() # clang native
47+
target_compile_options(libdivide INTERFACE "$<$<CONFIG:${BUILD_NAME}>:-fsanitize=address;-fsanitize=undefined;-fno-sanitize-recover=all;-fno-omit-frame-pointer;-U_DLL;-U_MT;-DDEBUG;-O1;-g>")
48+
target_link_options(libdivide INTERFACE "$<$<CONFIG:${BUILD_NAME}>:-fsanitize=address>")
49+
endif()
50+
elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU")
51+
target_compile_options(libdivide INTERFACE "$<$<CONFIG:${BUILD_NAME}>:-fsanitize=address;-fsanitize=undefined;-fno-sanitize-recover=all;-fno-omit-frame-pointer;-DDEBUG;-O1;-g>")
52+
target_link_options(libdivide INTERFACE "$<$<CONFIG:${BUILD_NAME}>:-fsanitize=address;-fsanitize=undefined>")
53+
endif()

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# libdivide
2-
[![Build Status](https://ci.appveyor.com/api/projects/status/github/ridiculousfish/libdivide?branch=master&svg=true)](https://ci.appveyor.com/project/kimwalisch/libdivide)
2+
[![Build Status](https://github.com/ridiculousfish/libdivide/actions/workflows/canary_build.yml/badge.svg)](https://github.com/ridiculousfish/libdivide/actions/workflows/canary_build.yml)
33
[![Github Releases](https://img.shields.io/github/release/ridiculousfish/libdivide.svg)](https://github.com/ridiculousfish/libdivide/releases)
44

55
```libdivide.h``` is a header-only C/C++ library for optimizing integer division.

libdivide.h

+9-2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,15 @@
3434
#include <arm_neon.h>
3535
#endif
3636

37+
// Clang-cl prior to Visual Studio 2022 doesn't include __umulh/__mulh intrinsics
38+
#if defined(_MSC_VER) && defined(LIBDIVIDE_X86_64) && (!defined(__clang__) || _MSC_VER>1930)
39+
#define LIBDIVIDE_X64_INTRINSICS
40+
#endif
41+
3742
#if defined(_MSC_VER)
43+
#if defined(LIBDIVIDE_X64_INTRINSICS)
3844
#include <intrin.h>
45+
#endif
3946
#pragma warning(push)
4047
// disable warning C4146: unary minus operator applied
4148
// to unsigned type, result still unsigned
@@ -325,7 +332,7 @@ static LIBDIVIDE_INLINE int32_t libdivide_mullhi_s32(int32_t x, int32_t y) {
325332
}
326333

327334
static LIBDIVIDE_INLINE uint64_t libdivide_mullhi_u64(uint64_t x, uint64_t y) {
328-
#if defined(LIBDIVIDE_VC) && defined(LIBDIVIDE_X86_64)
335+
#if defined(LIBDIVIDE_X64_INTRINSICS)
329336
return __umulh(x, y);
330337
#elif defined(HAS_INT128_T)
331338
__uint128_t xl = x, yl = y;
@@ -351,7 +358,7 @@ static LIBDIVIDE_INLINE uint64_t libdivide_mullhi_u64(uint64_t x, uint64_t y) {
351358
}
352359

353360
static LIBDIVIDE_INLINE int64_t libdivide_mullhi_s64(int64_t x, int64_t y) {
354-
#if defined(LIBDIVIDE_VC) && defined(LIBDIVIDE_X86_64)
361+
#if defined(LIBDIVIDE_X64_INTRINSICS)
355362
return __mulh(x, y);
356363
#elif defined(HAS_INT128_T)
357364
__int128_t xl = x, yl = y;

test/DivideTest.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ class DivideTest {
121121
PRINT_ERROR(F(", but got "));
122122
PRINT_ERROR(result);
123123
PRINT_ERROR(F("\n"));
124-
exit(1);
124+
TEST_FAIL();
125125
}
126126
}
127127

@@ -162,7 +162,7 @@ class DivideTest {
162162
PRINT_ERROR(F(", but got "));
163163
PRINT_ERROR(result);
164164
PRINT_ERROR(F("\n"));
165-
exit(1);
165+
TEST_FAIL();
166166
} else {
167167
#if 0
168168
std::cout << "vec" << (CHAR_BIT * sizeof(VecType)) << " success for: " << numer << " / " << denom << " = " << result << std::endl;
@@ -325,7 +325,7 @@ class DivideTest {
325325
PRINT_ERROR(F(", but got "));
326326
PRINT_ERROR(recovered);
327327
PRINT_ERROR(F("\n"));
328-
exit(1);
328+
TEST_FAIL();
329329
}
330330

331331
test_edgecase_numerators(denom, the_divider);

0 commit comments

Comments
 (0)