1+ # CMakeLists.txt for C/C++ Testing with CI/CD Example
2+ #
3+ # CMake is a cross-platform build system generator that creates native build files
4+ # (Makefiles on Unix, Visual Studio projects on Windows, etc.) from this configuration.
5+ #
6+ # Author: M A Chatterjee <deftio [at] deftio [dot] com>
7+ #
8+ # Usage:
9+ # mkdir build # Create a build directory (out-of-source build)
10+ # cd build # Enter the build directory
11+ # cmake .. # Generate build files
12+ # make # Build the project
13+ # make test # Run tests
14+ # make coverage # Generate coverage report (if enabled)
15+
16+ # Minimum CMake version required
17+ # Version 3.10 is widely available and supports modern CMake features
18+ cmake_minimum_required (VERSION 3.10)
19+
20+ # Project definition
21+ # This sets the project name and specifies we're using C language
22+ # VERSION follows semantic versioning (major.minor.patch)
23+ project (CTestingExample
24+ VERSION 1.0.4
25+ DESCRIPTION "Simple C library with unit testing and code coverage"
26+ LANGUAGES C)
27+
28+ # Set C standard
29+ # C99 is the minimum required, but the code is compatible with all later standards
30+ # Users can override with: cmake -DCMAKE_C_STANDARD=11 (or 17, 23, etc.)
31+ if (NOT CMAKE_C_STANDARD)
32+ set (CMAKE_C_STANDARD 99)
33+ endif ()
34+ set (CMAKE_C_STANDARD_REQUIRED ON )
35+ # Allow newer standards if available
36+ set (CMAKE_C_EXTENSIONS OFF )
37+
38+ # Compiler flags for all builds
39+ # -Wall: Enable all common warnings
40+ # -Wextra: Enable extra warning flags
41+ add_compile_options (-Wall -Wextra)
42+
43+ # Option to enable code coverage (default: ON)
44+ # Users can disable with: cmake -DENABLE_COVERAGE=OFF ..
45+ option (ENABLE_COVERAGE "Enable code coverage reporting" ON )
46+
47+ # Coverage configuration
48+ # Code coverage requires special compiler flags to instrument the code
49+ if (ENABLE_COVERAGE)
50+ # Check if we're using GCC or Clang (both support gcov-style coverage)
51+ if (CMAKE_C_COMPILER_ID MATCHES "GNU|Clang" )
52+ message (STATUS "Code coverage enabled" )
53+
54+ # Add coverage flags to both compilation and linking
55+ # -fprofile-arcs: Insert arc-based program flow instrumentation
56+ # -ftest-coverage: Produce .gcno files for gcov
57+ # --coverage: Shorthand that enables both flags above (alternative)
58+ add_compile_options (-fprofile-arcs -ftest-coverage)
59+ add_link_options (-fprofile-arcs -ftest-coverage)
60+
61+ # Use -O0 (no optimization) for accurate coverage data
62+ # Optimizations can eliminate code paths and skew coverage metrics
63+ set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0" )
64+ else ()
65+ message (WARNING "Code coverage requested but compiler ${CMAKE_C_COMPILER_ID} is not supported" )
66+ set (ENABLE_COVERAGE OFF )
67+ endif ()
68+ endif ()
69+
70+ # Library definition
71+ # Create a static library from our source files
72+ # STATIC means the library will be linked statically (included in the executable)
73+ add_library (testlib STATIC
74+ lib.c
75+ lib.h
76+ )
77+
78+ # Include directories for the library
79+ # PUBLIC means these includes are needed by both the library and its users
80+ target_include_directories (testlib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} )
81+
82+ # Test executable
83+ # This creates the test program that will exercise our library
84+ add_executable (test -library
85+ test -library.c
86+ )
87+
88+ # Link the test executable with our library
89+ # Also link with math library (m) and ncurses for demonstration
90+ target_link_libraries (test -library
91+ testlib # Our library
92+ m # Math library (for mathematical functions)
93+ ncurses # NCurses library (for terminal UI, if needed)
94+ )
95+
96+ # Enable testing support
97+ # This must be called to use CTest (CMake's testing framework)
98+ enable_testing ()
99+
100+ # Register our test executable with CTest
101+ # NAME: How the test appears in test reports
102+ # COMMAND: What to run (our test executable)
103+ add_test (
104+ NAME LibraryTests
105+ COMMAND test -library
106+ )
107+
108+ # Custom target for coverage report
109+ # This creates a 'make coverage' command that runs tests and generates reports
110+ if (ENABLE_COVERAGE)
111+ # Find required coverage tools
112+ find_program (GCOV_EXECUTABLE gcov)
113+ find_program (LCOV_EXECUTABLE lcov)
114+ find_program (GENHTML_EXECUTABLE genhtml)
115+
116+ if (GCOV_EXECUTABLE)
117+ # Create custom target for coverage
118+ add_custom_target (coverage
119+ # First, clean any existing coverage data
120+ COMMAND ${CMAKE_COMMAND} -E remove_directory coverage
121+ COMMAND ${CMAKE_COMMAND} -E make_directory coverage
122+
123+ # Run the tests to generate coverage data
124+ COMMAND ${CMAKE_CTEST_COMMAND} --output -on -failure
125+
126+ # Process coverage data with gcov
127+ COMMAND ${GCOV_EXECUTABLE} -b -c lib.c
128+
129+ # Optional: If lcov is available, generate HTML report
130+ COMMAND ${CMAKE_COMMAND} -E echo "Coverage report generated in *.gcov files"
131+
132+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
133+ DEPENDS test -library
134+ COMMENT "Generating code coverage report..."
135+ )
136+
137+ # If lcov is available, add HTML report generation
138+ if (LCOV_EXECUTABLE AND GENHTML_EXECUTABLE)
139+ add_custom_command (TARGET coverage POST_BUILD
140+ COMMAND ${LCOV_EXECUTABLE} --capture --directory . --output -file coverage.info --ignore -errors unused,unsupported
141+ COMMAND ${LCOV_EXECUTABLE} --remove coverage.info '*/test -library.c' --output -file coverage.info --ignore -errors unused,unsupported
142+ COMMAND ${GENHTML_EXECUTABLE} coverage.info --output -directory coverage --ignore -errors unused,unsupported
143+ COMMAND ${CMAKE_COMMAND} -E echo "HTML coverage report generated in coverage/index.html"
144+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
145+ )
146+ endif ()
147+ else ()
148+ message (STATUS "gcov not found - coverage target will not be available" )
149+ endif ()
150+ endif ()
151+
152+ # Installation rules (optional)
153+ # These define how to install the library for system-wide use
154+ install (TARGETS testlib
155+ LIBRARY DESTINATION lib
156+ ARCHIVE DESTINATION lib
157+ )
158+
159+ install (FILES lib.h
160+ DESTINATION include
161+ )
162+
163+ # Print configuration summary
164+ message (STATUS "" )
165+ message (STATUS "Configuration Summary:" )
166+ message (STATUS " C Compiler: ${CMAKE_C_COMPILER} " )
167+ message (STATUS " Build Type: ${CMAKE_BUILD_TYPE} " )
168+ message (STATUS " Coverage Enabled: ${ENABLE_COVERAGE} " )
169+ message (STATUS "" )
170+ message (STATUS "Build with:" )
171+ message (STATUS " mkdir build && cd build" )
172+ message (STATUS " cmake .." )
173+ message (STATUS " make" )
174+ message (STATUS " make test" )
175+ if (ENABLE_COVERAGE)
176+ message (STATUS " make coverage # Generate coverage report" )
177+ endif ()
178+ message (STATUS "" )
0 commit comments