Skip to content

Commit 21eaa5d

Browse files
authored
Add tl_lookup_positional (#18)
1 parent 8cfaa1b commit 21eaa5d

15 files changed

Lines changed: 159 additions & 79 deletions

File tree

.github/workflows/test.yaml

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,35 +35,31 @@ jobs:
3535
- name: Checkout code
3636
uses: actions/checkout@v6
3737

38-
- name: Install mise
38+
- name: Install Dependencies
3939
run: |
4040
curl https://mise.run | sh
4141
mise settings experimental=true
42+
mise trust
43+
mise install
4244
43-
- name: Trust workspace
44-
run: mise trust
45+
- name: Configure
46+
run: mise exec -- make configure
4547

46-
- name: Install dependencies
47-
run: mise exec -- mise install
48+
- name: Build
49+
run: mise exec -- make build
4850

49-
- name: Configure project
50-
run: mise exec -- make configure
51+
- name: Test
52+
run: mise exec -- make test
5153

52-
- name: Run formatting checks
54+
- name: Formatting
5355
run: mise exec -- make format
5456

55-
- name: Run lint
57+
- name: Linting
5658
run: mise exec -- make lint
5759

58-
- name: Run static analysis
60+
- name: Static Analysis
5961
run: mise exec -- make check
6062

61-
- name: Build project
62-
run: mise exec -- make build
63-
64-
- name: Run tests
65-
run: mise exec -- make test
66-
6763
test-amd64:
6864
needs: test
6965
runs-on: ubuntu-latest

.vscode/c_cpp_properties.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@
22
"configurations": [
33
{
44
"name": "Mac",
5-
"compileCommands": "${workspaceFolder}/build/compile_commands.json",
5+
"includePath": ["${workspaceFolder}/**"],
6+
"macFrameworkPath": [
7+
"/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks"
8+
],
69
"compilerPath": "/usr/bin/clang",
10+
"compileCommands": "${workspaceFolder}/build/compile_commands.json",
711
"cStandard": "c11",
812
"intelliSenseMode": "macos-clang-arm64"
913
}

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,15 @@
1919
},
2020
"cSpell.words": [
2121
"armv",
22+
"BINDIR",
2223
"CMSIS",
2324
"cppcheck",
2425
"ctest",
2526
"Dryrun",
2627
"eabi",
2728
"endforeach",
29+
"endfunction",
30+
"INCLUDEDIR",
2831
"libnewlib",
2932
"noninteractive",
3033
"tinyclib",

CMakeLists.txt

Lines changed: 18 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,27 @@ cmake_minimum_required(VERSION 3.25)
33
project(tinyclib VERSION 0.3.1 LANGUAGES C)
44

55
# Settings and options
6-
option(TL_BUILD_TESTS "Build tinyclib tests" ${PROJECT_IS_TOP_LEVEL})
76
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
87
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
98
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
109
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
10+
option(TL_BUILD_TESTS "Build tinyclib tests" ${PROJECT_IS_TOP_LEVEL})
11+
12+
function(tl_configure_c_target target)
13+
set_property(TARGET ${target} PROPERTY C_STANDARD 11)
14+
set_property(TARGET ${target} PROPERTY C_STANDARD_REQUIRED ON)
15+
set_property(TARGET ${target} PROPERTY C_EXTENSIONS OFF)
16+
endfunction()
1117

1218
# Dependencies
19+
include(CTest)
1320
include(FetchContent)
21+
1422
# Sources
1523
file(GLOB SOURCES CONFIGURE_DEPENDS src/*.c)
16-
1724
# Add the library (BUILD_SHARED_LIBS is handled by CMake)
1825
add_library(tinyclib ${SOURCES})
19-
20-
# Set the C standard
21-
set_property(TARGET tinyclib PROPERTY C_STANDARD 11)
22-
set_property(TARGET tinyclib PROPERTY C_STANDARD_REQUIRED ON)
23-
set_property(TARGET tinyclib PROPERTY C_EXTENSIONS OFF)
26+
tl_configure_c_target(tinyclib)
2427

2528
# Set include directories for build and install
2629
target_include_directories(
@@ -29,6 +32,14 @@ target_include_directories(
2932
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
3033
$<INSTALL_INTERFACE:include>
3134
)
35+
set_target_properties(tinyclib PROPERTIES POSITION_INDEPENDENT_CODE ON) # support shared libraries
36+
add_library(tinyclib::tinyclib ALIAS tinyclib) # add a namespace alias for modern linking
37+
38+
# Tests
39+
if(TL_BUILD_TESTS)
40+
add_subdirectory(third_party/unity)
41+
add_subdirectory(tests)
42+
endif()
3243

3344
# Install targets and headers
3445
include(GNUInstallDirs)
@@ -71,38 +82,3 @@ install(
7182
NAMESPACE tinyclib::
7283
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/tinyclib
7384
)
74-
75-
# Add a namespace alias for modern linking
76-
add_library(tinyclib::tinyclib ALIAS tinyclib)
77-
78-
# Support shared libraries
79-
set_target_properties(tinyclib PROPERTIES POSITION_INDEPENDENT_CODE ON)
80-
81-
# Build tests
82-
if(TL_BUILD_TESTS)
83-
include(CTest)
84-
include(FetchContent)
85-
set(TEST_TARGETS
86-
tl_app_test
87-
tl_config_test
88-
tl_debug_test
89-
tl_error_test
90-
tl_flag_test
91-
tl_test_test
92-
)
93-
94-
# FetchContent for Unity testing framework
95-
FetchContent_Declare(
96-
Unity
97-
GIT_REPOSITORY https://github.com/ThrowTheSwitch/Unity.git
98-
GIT_TAG v2.6.1
99-
)
100-
FetchContent_MakeAvailable(Unity)
101-
102-
enable_testing()
103-
foreach(t IN LISTS TEST_TARGETS)
104-
add_executable(${t} tests/unit/${t}.c)
105-
target_link_libraries(${t} unity tinyclib)
106-
add_test(NAME ${t} COMMAND ${t})
107-
endforeach()
108-
endif()

Makefile

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,70 @@
11
.DEFAULT_GOAL := help
22

3-
BUILD_DIR := build
43
CLANG_FORMAT := $(shell if command -v clang-format >/dev/null 2>&1; then echo clang-format; fi)
54
CLANG_TIDY := $(shell if command -v clang-tidy >/dev/null 2>&1; then echo clang-tidy; fi)
65
CPPCHECK := $(shell if command -v cppcheck >/dev/null 2>&1; then echo cppcheck; fi)
76
CLANG_TIDY_EXTRA_ARGS := $(shell if [ "$$(uname)" = "Darwin" ]; then echo "--extra-arg=--sysroot=$$(xcrun --show-sdk-path)"; fi)
87

98
SRC_FILES := src/*.c include/*.h
109
TEST_FILES := tests/unit/*.c
11-
EXAMPLE_FILES := $(wildcard examples/*/*.c)
12-
ALL_FILES := $(SRC_FILES) $(TEST_FILES) $(EXAMPLE_FILES)
10+
CMD_FILES := $(wildcard cmd/*/*.c cmd/*/*.h)
11+
ALL_FILES := $(SRC_FILES) $(TEST_FILES) $(CMD_FILES)
1312

1413
PRESET ?= default
14+
JOBS ?= 4
15+
PROJECT_DIR := $(CURDIR)
16+
BUILD_ROOT := build
17+
PRESET_BUILD_DIR := $(if $(filter default,$(PRESET)),$(BUILD_ROOT),$(BUILD_ROOT)/$(PRESET))
1518

16-
.PHONY: help install build clean clean-bin test format lint check check-all fix
19+
.PHONY: help configure build clean clean-bin clean-cache test format lint check check-all fix
1720

1821
help: ## Show available make targets
1922
@echo "Usage: make <target>"
2023
@echo ""
2124
@echo "Targets:"
2225
@awk 'BEGIN {FS = ":.*## "} /^[a-zA-Z_-]+:.*## / {printf " %-15s %s\n", $$1, $$2}' $(MAKEFILE_LIST)
2326

24-
configure: ## Configure cmake
27+
configure: ## Configure cmake (use PRESET=release for release mode)
2528
cmake --preset $(PRESET)
2629

27-
build: ## Build the project
28-
@test -d "$(BUILD_DIR)" || cmake --preset $(PRESET)
29-
cmake --build --preset $(PRESET)
30+
build: ## Build the project (use PRESET=release for release mode)
31+
cmake --preset $(PRESET)
32+
cmake --build --preset $(PRESET) -j $(JOBS)
33+
34+
clean: ## Remove build directories
35+
@test -n "$(PROJECT_DIR)" && [ "$(PROJECT_DIR)" != "/" ]
36+
rm -rf "$(PROJECT_DIR)/$(BUILD_ROOT)"
3037

31-
clean: ## Remove build directory
32-
@test -n "$(CURDIR)" && [ "$(CURDIR)" != "/" ]
33-
rm -rf "$(CURDIR)/$(BUILD_DIR)"
38+
clean-bin: ## Remove built binaries for the selected preset
39+
@test -n "$(PROJECT_DIR)" && [ "$(PROJECT_DIR)" != "/" ]
40+
@test -d "$(PROJECT_DIR)/$(PRESET_BUILD_DIR)/cmd/bin" || exit 0
41+
find "$(PROJECT_DIR)/$(PRESET_BUILD_DIR)/cmd/bin" -mindepth 1 -delete
3442

35-
clean-bin: ## Remove built binaries from the build directory
36-
@test -n "$(CURDIR)" && [ "$(CURDIR)" != "/" ]
37-
@test -d "$(CURDIR)/$(BUILD_DIR)/bin" || exit 0
38-
find "$(CURDIR)/$(BUILD_DIR)/bin" -mindepth 1 -delete
43+
clean-cache: ## Remove CMake cache for the selected preset
44+
@test -n "$(PROJECT_DIR)" && [ "$(PROJECT_DIR)" != "/" ]
45+
rm -f "$(PROJECT_DIR)/$(PRESET_BUILD_DIR)/CMakeCache.txt"
3946

4047
test: ## Run tests
41-
ctest --preset default
48+
@test -f "$(PROJECT_DIR)/$(PRESET_BUILD_DIR)/CMakeCache.txt" || cmake --preset $(PRESET)
49+
cmake --build --preset $(PRESET) -j $(JOBS)
50+
ctest --preset $(PRESET)
4251

4352
format: ## Check code formatting
4453
@test -n "$(CLANG_FORMAT)" || { echo "error: clang-format not found"; exit 1; }
4554
$(CLANG_FORMAT) --dry-run --Werror $(ALL_FILES) --verbose
4655

4756
lint: ## Check code linting
4857
@test -n "$(CLANG_TIDY)" || { echo "error: clang-tidy not found"; exit 1; }
49-
$(CLANG_TIDY) -p $(BUILD_DIR) $(CLANG_TIDY_EXTRA_ARGS) \
50-
--header-filter="^$(CURDIR)/(src|include|tests)/" src/*.c tests/unit/*.c
58+
@test -f "$(PRESET_BUILD_DIR)/compile_commands.json" || cmake --preset default
59+
$(CLANG_TIDY) --config-file=$(PROJECT_DIR)/.clang-tidy -p $(PRESET_BUILD_DIR) $(CLANG_TIDY_EXTRA_ARGS) \
60+
--header-filter="^$(PROJECT_DIR)/(src|include|tests)/" src/*.c tests/unit/*.c
5161

5262
check: ## Static analysis
5363
@test -n "$(CPPCHECK)" || { echo "error: cppcheck not found"; exit 1; }
64+
@test -f "$(PRESET_BUILD_DIR)/compile_commands.json" || cmake --preset default
5465
$(CPPCHECK) --enable=warning,style,performance,portability --error-exitcode=1 \
55-
--check-level=exhaustive --project=$(BUILD_DIR)/compile_commands.json \
56-
--suppress=missingIncludeSystem -i$(BUILD_DIR)
66+
--check-level=exhaustive --project=$(PRESET_BUILD_DIR)/compile_commands.json \
67+
--suppress=missingIncludeSystem -i$(PRESET_BUILD_DIR)
5768

5869
check-all: test format lint check ## Run all checks
5970

include/tl_flag.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,15 @@ size_t tl_count_flag(const char *flag);
123123
*/
124124
const char *tl_get_flag_at(const char *flag, size_t index);
125125

126+
/**
127+
* @brief Looks up a specific positional argument by value.
128+
*
129+
* @param value The positional value to look up.
130+
*
131+
* @return true if the positional is found, false otherwise.
132+
*/
133+
bool tl_lookup_positional(const char *value);
134+
126135
/**
127136
* @brief Returns the number of positional arguments.
128137
*

src/tl_flag.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,18 @@ const char *tl_get_flag_at(const char *flag, size_t index) {
291291
return NULL;
292292
}
293293

294+
bool tl_lookup_positional(const char *value) {
295+
if (!value) {
296+
return false;
297+
}
298+
for (size_t i = 0; i < positional_count; i++) {
299+
if (strcmp(positionals[i], value) == 0) {
300+
return true;
301+
}
302+
}
303+
return false;
304+
}
305+
294306
size_t tl_count_positional(void) {
295307
return positional_count;
296308
}

tests/CMakeLists.txt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
set(TEST_BIN_DIR "${PROJECT_BINARY_DIR}/tests/bin")
2+
3+
set(UNIT_TEST_TARGETS
4+
app_test
5+
config_test
6+
debug_test
7+
error_test
8+
flag_test
9+
test_test
10+
)
11+
12+
foreach(test_target IN LISTS UNIT_TEST_TARGETS)
13+
string(REGEX REPLACE "_test$" "" test_name "${test_target}")
14+
set(test_binary "tl_${test_name}")
15+
add_executable(${test_binary} unit/${test_target}.c)
16+
target_link_libraries(${test_binary} PRIVATE tinyclib unity)
17+
target_include_directories(${test_binary} PRIVATE ${PROJECT_SOURCE_DIR}/src)
18+
set_target_properties(${test_binary} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${TEST_BIN_DIR})
19+
add_test(NAME ${test_binary} COMMAND ${test_binary})
20+
endforeach()

0 commit comments

Comments
 (0)