Skip to content
Open
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
24 changes: 24 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,30 @@ jobs:
run: |
docker run --rm --volume $(pwd):/note-c/ --workdir /note-c/ --entrypoint ./scripts/run_cppcheck.sh ghcr.io/blues/note_c_ci:latest

run_macos_unit_tests:
runs-on: macos-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Configure
run: cmake -B build -DNOTE_C_BUILD_TESTS=ON

- name: Build
run: cmake --build build --parallel $(sysctl -n hw.ncpu)

# NOTE: ctest is not run here. A subset of tests that rely on FFF
# symbol interposition fail on macOS due to two-level namespace
# linking. The build step above verifies that all sources and tests
# compile and link successfully.
#
# Even with -Wl,-flat_namespace, intra-library calls within the
# note_c dylib are resolved at link time as direct calls, so FFF
# fakes in the test executable cannot interpose them. Fully fixing
# this would require linking note-c as a static library for tests
# or using a different mocking approach on macOS.

publish_ci_image:
runs-on: ubuntu-latest
# Make sure unit tests unit tests passed before publishing.
Expand Down
230 changes: 171 additions & 59 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.20)
cmake_minimum_required(VERSION 3.21)
cmake_policy(SET CMP0095 NEW)

if ("${CMAKE_BINARY_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}")
Expand All @@ -16,7 +16,7 @@ if(NOT EXISTS ${PROJECT_BINARY_DIR}/.gitignore)
endif()

option(NOTE_C_BUILD_DOCS "Build docs." OFF)
option(NOTE_C_BUILD_TESTS "Build tests." ON)
option(NOTE_C_BUILD_TESTS "Build tests." ${PROJECT_IS_TOP_LEVEL})
option(NOTE_C_COVERAGE "Compile for test NOTE_C_COVERAGE reporting." OFF)
option(NOTE_C_LOW_MEM "Build the library tailored for low memory usage." OFF)
option(NOTE_C_MEM_CHECK "Run tests with Valgrind." OFF)
Expand All @@ -27,61 +27,62 @@ option(NOTE_C_SINGLE_PRECISION "Use single precision for JSON floating point num
option(NOTE_C_HEARTBEAT_CALLBACK "Enable heartbeat callback support." OFF)

set(NOTE_C_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR})
add_library(note_c SHARED)
target_sources(
note_c
PRIVATE
${NOTE_C_SRC_DIR}/n_atof.c
${NOTE_C_SRC_DIR}/n_b64.c
${NOTE_C_SRC_DIR}/n_cjson.c
${NOTE_C_SRC_DIR}/n_cjson_helpers.c
${NOTE_C_SRC_DIR}/n_cobs.c
${NOTE_C_SRC_DIR}/n_const.c
${NOTE_C_SRC_DIR}/n_ftoa.c
${NOTE_C_SRC_DIR}/n_helpers.c
${NOTE_C_SRC_DIR}/n_hooks.c
${NOTE_C_SRC_DIR}/n_i2c.c
${NOTE_C_SRC_DIR}/n_md5.c
${NOTE_C_SRC_DIR}/n_printf.c
${NOTE_C_SRC_DIR}/n_request.c
${NOTE_C_SRC_DIR}/n_serial.c
${NOTE_C_SRC_DIR}/n_str.c
)
target_compile_options(
note_c
PRIVATE
-Wall
-Wextra
-Wpedantic
-Werror
-Og
-ggdb
PUBLIC
-m32
-mfpmath=sse
-msse2
)
target_include_directories(
note_c
PUBLIC ${NOTE_C_SRC_DIR}
)
target_link_directories(
note_c
PUBLIC
/lib32
/usr/lib32
/usr/lib/gcc/x86_64-linux-gnu/12/32
)
target_link_options(
note_c
PUBLIC
-m32
-Wl,-melf_i386

# Detect whether the system already provides strlcpy/strlcat (macOS, *BSD).
# When present, we skip the bundled implementations in n_str.c and define
# guards so note.h doesn't redeclare them (which collides with the platform's
# fortified macros).
include(CheckSymbolExists)
check_symbol_exists(strlcpy "string.h" HAVE_STRLCPY)
check_symbol_exists(strlcat "string.h" HAVE_STRLCAT)

set(NOTE_C_SOURCES
${NOTE_C_SRC_DIR}/n_atof.c
${NOTE_C_SRC_DIR}/n_b64.c
${NOTE_C_SRC_DIR}/n_cjson.c
${NOTE_C_SRC_DIR}/n_cjson_helpers.c
${NOTE_C_SRC_DIR}/n_cobs.c
${NOTE_C_SRC_DIR}/n_const.c
${NOTE_C_SRC_DIR}/n_ftoa.c
${NOTE_C_SRC_DIR}/n_helpers.c
${NOTE_C_SRC_DIR}/n_hooks.c
${NOTE_C_SRC_DIR}/n_i2c.c
${NOTE_C_SRC_DIR}/n_md5.c
${NOTE_C_SRC_DIR}/n_printf.c
${NOTE_C_SRC_DIR}/n_request.c
${NOTE_C_SRC_DIR}/n_serial.c
)
# n_str.c provides weak strlcpy/strlcat. On systems that already have them
# the file won't compile because the platform headers define these as
# fortified macros that conflict with the function definitions.
if(NOT HAVE_STRLCPY OR NOT HAVE_STRLCAT)
list(APPEND NOTE_C_SOURCES ${NOTE_C_SRC_DIR}/n_str.c)
endif()
# ---------------------------------------------------------------------------
# note_c_lib — static library for downstream consumers.
#
# Projects that include note-c as a submodule can simply do:
#
# add_subdirectory(note-c)
# target_link_libraries(my_app PRIVATE note_c_lib)
#
# This target carries the include path and platform compile definitions
# (HAVE_STRLCPY, etc.) but no test flags, 32-bit cross-compile options,
# or other CI-specific settings.
# ---------------------------------------------------------------------------
add_library(note_c_lib STATIC ${NOTE_C_SOURCES})
target_include_directories(note_c_lib PUBLIC ${NOTE_C_SRC_DIR})

if(HAVE_STRLCPY)
target_compile_definitions(note_c_lib PUBLIC HAVE_STRLCPY)
endif()
if(HAVE_STRLCAT)
target_compile_definitions(note_c_lib PUBLIC HAVE_STRLCAT)
endif()

if(NOTE_C_LOW_MEM)
target_compile_definitions(
note_c
note_c_lib
PUBLIC
NOTE_C_LOW_MEM
)
Expand All @@ -90,15 +91,15 @@ else()
# about an empty translation unit, so we only add it to the build if
# NOTE_C_LOW_MEM is false.
target_sources(
note_c
note_c_lib
PRIVATE
${NOTE_C_SRC_DIR}/n_ua.c
)
endif()

if(NOTE_C_NO_LIBC)
target_link_options(
note_c
note_c_lib
PRIVATE
-nostdlib
-nodefaultlibs
Expand All @@ -108,37 +109,148 @@ endif()

if(NOTE_NODEBUG)
target_compile_definitions(
note_c
note_c_lib
PUBLIC
NOTE_NODEBUG
)
endif()

if(NOTE_C_SHOW_MALLOC)
target_compile_definitions(
note_c
note_c_lib
PUBLIC
NOTE_C_SHOW_MALLOC
)
endif()

if(NOTE_C_SINGLE_PRECISION)
target_compile_definitions(
note_c
note_c_lib
PUBLIC
NOTE_C_SINGLE_PRECISION
)
endif()

if(NOTE_C_HEARTBEAT_CALLBACK)
target_compile_definitions(
note_c
note_c_lib
PUBLIC
NOTE_C_HEARTBEAT_CALLBACK
)
endif()

# ---------------------------------------------------------------------------
# note_c — shared library used by the unit test harness.
#
# This target adds -Werror, 32-bit cross-compile flags (Linux CI), FFF
# interposition support (macOS), and the NOTE_C_TEST define. It is NOT
# intended for downstream consumption.
# ---------------------------------------------------------------------------
if(NOTE_C_BUILD_TESTS)
add_library(note_c SHARED ${NOTE_C_SOURCES})
target_include_directories(note_c PUBLIC ${NOTE_C_SRC_DIR})

if(HAVE_STRLCPY)
target_compile_definitions(note_c PUBLIC HAVE_STRLCPY)
endif()
if(HAVE_STRLCAT)
target_compile_definitions(note_c PUBLIC HAVE_STRLCAT)
endif()

target_compile_options(
note_c
PRIVATE
-Wall
-Wextra
-Wpedantic
-Werror
-Og
-ggdb
)
# The Linux CI runs tests in 32-bit mode. These flags are x86-specific and
# unavailable on Apple toolchains or non-x86 architectures.
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|i[3-6]86")
target_compile_options(note_c PUBLIC -m32 -mfpmath=sse -msse2)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|i[3-6]86")
target_link_directories(
note_c
PUBLIC
/lib32
/usr/lib32
/usr/lib/gcc/x86_64-linux-gnu/12/32
)
target_link_options(
note_c
PUBLIC
-m32
-Wl,-melf_i386
)
endif()
if(APPLE)
# Use flat namespace so test fakes (FFF) can interpose library symbols
target_link_options(note_c PRIVATE -Wl,-flat_namespace)
endif()

if(NOTE_C_LOW_MEM)
target_compile_definitions(
note_c
PUBLIC
NOTE_C_LOW_MEM
)
else()
# This file is empty if NOTE_C_LOW_MEM is defined, which leads to a warning
# about an empty translation unit, so we only add it to the build if
# NOTE_C_LOW_MEM is false.
target_sources(
note_c
PRIVATE
${NOTE_C_SRC_DIR}/n_ua.c
)
endif()

if(NOTE_C_NO_LIBC)
target_link_options(
note_c
PRIVATE
-nostdlib
-nodefaultlibs
LINKER:--no-undefined
)
endif()

if(NOTE_NODEBUG)
target_compile_definitions(
note_c
PUBLIC
NOTE_NODEBUG
)
endif()

if(NOTE_C_SHOW_MALLOC)
target_compile_definitions(
note_c
PUBLIC
NOTE_C_SHOW_MALLOC
)
endif()

if(NOTE_C_SINGLE_PRECISION)
target_compile_definitions(
note_c
PUBLIC
NOTE_C_SINGLE_PRECISION
)
endif()

if(NOTE_C_HEARTBEAT_CALLBACK)
target_compile_definitions(
note_c
PUBLIC
NOTE_C_HEARTBEAT_CALLBACK
)
endif()

# Including CTest here rather than in test/CMakeLists.txt allows us to run
# ctest from the root build directory (e.g. build/ instead of build/test/).
# We also need to set MEMORYCHECK_COMMAND_OPTIONS before including this.
Expand Down
10 changes: 1 addition & 9 deletions n_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -2403,7 +2403,7 @@ uint32_t NoteMemAvailable(void)
objHeader *lastObj = NULL;
static long int maxsize = 35000;
for (long int i=maxsize; i>=(long int)sizeof(objHeader); i=i-sizeof(objHeader)) {
for (long int j=0;; j++) {
for (;;) {
objHeader *thisObj;
thisObj = (objHeader *) _Malloc(i);
if (thisObj == NULL) {
Expand All @@ -2416,16 +2416,8 @@ uint32_t NoteMemAvailable(void)
}

// Free the objects backwards
long int lastLength = 0;
long int lastLengthCount = 0;
uint32_t total = 0;
while (lastObj != NULL) {
if (lastObj->length != lastLength) {
lastLength = lastObj->length;
lastLengthCount = 1;
} else {
lastLengthCount++;
}
objHeader *thisObj = lastObj;
lastObj = lastObj->prev;
total += thisObj->length;
Expand Down
4 changes: 2 additions & 2 deletions n_ua.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ __attribute__((weak)) void NoteUserAgentUpdate(J *ua)
*/
/**************************************************************************/
#if defined(_MSC_VER)
J *NoteUserAgent()
J *NoteUserAgent(void)
#else
__attribute__((weak)) J *NoteUserAgent()
__attribute__((weak)) J *NoteUserAgent(void)
#endif
{

Expand Down
2 changes: 2 additions & 0 deletions scripts/check_libc_dependencies.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ LIBC_WHITELIST=(
"strchr"
"strcmp"
"strlen"
"strlcpy" # bundled in n_str.c; also available in glibc 2.38+
"strlcat" # bundled in n_str.c; also available in glibc 2.38+
"strncmp"
"strstr"
"strtol" # required by atoi in NoteGenEnvInt
Expand Down
Loading
Loading