Skip to content

Commit 8dc894e

Browse files
author
codethinki
committed
added optional program discovering and format target functions
1 parent 4af543c commit 8dc894e

4 files changed

Lines changed: 149 additions & 36 deletions

File tree

cth_assertions.cmake

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,4 +292,32 @@ function(cth_assert_program prog)
292292
endif()
293293

294294
cth_assert_true(${VAR_NAME} REASON "${ARG_REASON}")
295+
endfunction()
296+
297+
#[[.rst:
298+
.. command:: cth_assert_file
299+
300+
.. code-block:: cmake
301+
302+
cth_assert_file(<file> [REASON <reason>])
303+
304+
Asserts that a file exists and is not a directory.
305+
306+
:param file: Path to the file to check
307+
:type file: string
308+
:param REASON: Optional error message to display if the assertion fails
309+
:type REASON: string
310+
311+
:post: file exists and is not a directory or configuration terminates with FATAL_ERROR
312+
#]]
313+
function(cth_assert_file file)
314+
set(oneValueArgs REASON)
315+
cmake_parse_arguments(PARSE_ARGV 1 ARG "" "${oneValueArgs}" "")
316+
317+
if(NOT EXISTS "${file}" OR IS_DIRECTORY "${file}")
318+
if(NOT ARG_REASON)
319+
set(ARG_REASON "File '${file}' does not exist or is a directory")
320+
endif()
321+
_cth_assertion_failure("${ARG_REASON}")
322+
endif()
295323
endfunction()

cth_target_utilities.cmake

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -349,34 +349,75 @@ endfunction()
349349

350350

351351
#[[.rst:
352-
.. command:: cth_add_clang_format_target
352+
.. command:: cth_add_opt_clang_format_target
353353
354354
.. code-block:: cmake
355355
356-
cth_add_clang_format_target(<files...>)
356+
cth_add_opt_clang_format_target(<target_name> <files...>)
357357
358-
Creates a custom target named "format" that runs clang-format on specified files.
358+
Optionally creates a custom target that runs clang-format on specified files.
359+
Only creates the target if clang-format is available.
359360
361+
:param target_name: Name of the custom target to create
362+
:type target_name: string
360363
:param files: List of source files to format
361364
:type files: list of file paths
362365
363-
:pre: clang-format executable is available in PATH
364-
:post: A custom target named "format" is created that formats the specified files in-place
366+
:post: A custom target is created if clang-format is found; otherwise no target is created
365367
366368
.. note::
367369
- The format target uses ``-i`` flag to format files in-place
368370
- The ``-style=file`` flag means clang-format will look for a .clang-format configuration file
369371
- Files are formatted relative to CMAKE_SOURCE_DIR
372+
- Check if the target exists before depending on it in your build
370373
371-
.. warning::
372-
This function will fail if clang-format is not found in PATH.
374+
.. seealso::
375+
- ``cth_find_opt_clang_format()`` from cth_tool_utilities to locate clang-format optionally
376+
377+
#]]
378+
function(cth_add_opt_clang_format_target TARGET_NAME)
379+
cth_assert_not_empty(${TARGET_NAME} REASON "add_opt_clang_format_target requires a target name")
380+
381+
include(cth_tool_utilities)
382+
cth_find_opt_clang_format()
383+
384+
if(NOT CLANG_FORMAT_EXECUTABLE)
385+
message(STATUS "clang-format not found, skipping ${TARGET_NAME} target creation")
386+
return()
387+
endif()
388+
389+
set(FILES_TO_FORMAT ${ARGN})
390+
391+
add_custom_target(
392+
${TARGET_NAME}
393+
COMMAND ${CLANG_FORMAT_EXECUTABLE} -i -style=file ${FILES_TO_FORMAT}
394+
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
395+
COMMENT "Formatting all source files with clang-format..."
396+
VERBATIM
397+
)
398+
endfunction()
399+
400+
#[[.rst:
401+
.. command:: cth_add_clang_format_target
402+
403+
.. code-block:: cmake
404+
405+
cth_add_clang_format_target(<target_name> <files...>)
406+
407+
Creates a required custom target that runs clang-format on specified files.
408+
Terminates configuration with FATAL_ERROR if clang-format is not found.
409+
410+
:param target_name: Name of the custom target to create
411+
:param files: List of source files to format
412+
413+
:post: A custom target is created, or configuration terminates with FATAL_ERROR if clang-format not found
373414
374415
**Example usage:**
375416
376417
.. code-block:: cmake
377418
378-
# Format specific files
379419
cth_add_clang_format_target(
420+
format
380421
src/main.cpp
381422
src/utils.cpp
382423
include/header.hpp
@@ -385,26 +426,14 @@ endfunction()
385426
# Then run: cmake --build . --target format
386427
387428
.. seealso::
429+
- ``cth_add_opt_clang_format_target()`` for optional target creation
388430
- ``cth_find_clang_format()`` from cth_tool_utilities to locate clang-format
389431
- Create a .clang-format file in your project root to define formatting style
390432
391433
#]]
392434
function(cth_add_clang_format_target TARGET_NAME)
393-
cth_assert_not_empty(${TARGET_NAME} REASON "add_clang_format_target requires a target name")
394-
395435
include(cth_tool_utilities)
396436
cth_find_clang_format()
397437

398-
set(FILES_TO_FORMAT ${ARGN})
399-
400-
401-
402-
403-
add_custom_target(
404-
${TARGET_NAME}
405-
COMMAND ${CLANG_FORMAT_EXECUTABLE} -i -style=file ${FILES_TO_FORMAT}
406-
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
407-
COMMENT "Formatting all source files with clang-format..."
408-
VERBATIM
409-
)
438+
cth_add_opt_clang_format_target(${TARGET_NAME} ${ARGN})
410439
endfunction()

cth_tool_utilities.cmake

Lines changed: 69 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
include(cth_assertions)
55

66
#[[.rst:
7-
.. command:: cth_find_program
7+
.. command:: cth_find_optional_program
88
99
.. code-block:: cmake
1010
11-
cth_find_program(<out_var> <prog> [args...])
11+
cth_find_optional_program(<out_var> <prog> [args...])
1212
1313
Locates an external program and exports its path to the parent scope.
1414
@@ -18,12 +18,43 @@ include(cth_assertions)
1818
:param args: Additional arguments to pass to find_program (e.g., PATHS, HINTS)
1919
:type args: optional arguments
2020
21-
:post: <OUT_VAR> variable is set in PARENT_SCOPE with the full path to the program, or configuration terminates with FATAL_ERROR if not found
21+
:post: <OUT_VAR> variable is set in PARENT_SCOPE with the full path to the program if found, or an empty string if not found
22+
23+
.. note::
24+
Unlike ``cth_find_program()``, this function does not error if the program is not found.
25+
Check if the result variable is empty to determine if the program was found.
26+
2227
#]]
23-
function(cth_find_program OUT_VAR prog)
28+
function(cth_find_optional_program OUT_VAR prog)
2429

2530
find_program(${OUT_VAR} "${prog}" ${ARGN})
2631

32+
set(${OUT_VAR} "${${OUT_VAR}}" PARENT_SCOPE)
33+
endfunction()
34+
35+
#[[.rst:
36+
.. command:: cth_find_program
37+
38+
.. code-block:: cmake
39+
40+
cth_find_program(<out_var> <prog> [args...])
41+
42+
Locates a required external program and exports its path to the parent scope.
43+
Terminates configuration with FATAL_ERROR if not found.
44+
45+
:param OUT_VAR variable to export program path to
46+
:param prog: Name of the program to find
47+
:param args: Additional arguments to pass to find_program
48+
49+
:post: <OUT_VAR> variable is set in PARENT_SCOPE with the full path to the program, or configuration terminates with FATAL_ERROR if not found
50+
51+
.. seealso::
52+
See ``cth_find_optional_program()`` for a variant that does not error if the program is not found.
53+
54+
#]]
55+
function(cth_find_program OUT_VAR prog)
56+
cth_find_optional_program(${OUT_VAR} "${prog}" ${ARGN})
57+
2758
cth_assert_true(${OUT_VAR} REASON "Program '${prog}' not found")
2859

2960
set(${OUT_VAR} "${${OUT_VAR}}" PARENT_SCOPE)
@@ -63,31 +94,55 @@ function(cth_enable_build_cache)
6394
endfunction()
6495

6596
#[[.rst:
66-
.. command:: cth_find_clang_format
97+
.. command:: cth_find_opt_clang_format
6798
6899
.. code-block:: cmake
69100
70-
cth_find_clang_format()
101+
cth_find_opt_clang_format()
71102
72103
Locates the clang-format executable and exports its path to the parent scope.
104+
Does not error if clang-format is not found.
73105
74-
:post: CLANG_FORMAT_EXECUTABLE is set in PARENT_SCOPE with the full path to clang-format, or configuration terminates with FATAL_ERROR if not found
106+
:post: CLANG_FORMAT_EXECUTABLE is set in PARENT_SCOPE with the full path to clang-format, or an empty string if not found
75107
76108
.. note::
77-
The clang-format executable must be available in PATH.
109+
Check if CLANG_FORMAT_EXECUTABLE is empty to determine if clang-format was found.
78110
79-
.. warning::
80-
This function will fail with FATAL_ERROR if clang-format is not found.
81-
Ensure clang-format is installed and available in your system PATH.
111+
.. seealso::
112+
Use ``cth_add_clang_format_target()`` from cth_target_utilities to create a format target.
113+
114+
#]]
115+
function(cth_find_opt_clang_format)
116+
cth_find_optional_program(CLANG_FORMAT_EXECUTABLE clang-format)
117+
118+
if(CLANG_FORMAT_EXECUTABLE)
119+
message(STATUS "Found external clang-format: ${CLANG_FORMAT_EXECUTABLE}")
120+
endif()
121+
122+
set(CLANG_FORMAT_EXECUTABLE ${CLANG_FORMAT_EXECUTABLE} PARENT_SCOPE)
123+
endfunction()
124+
125+
#[[.rst:
126+
.. command:: cth_find_clang_format
127+
128+
.. code-block:: cmake
129+
130+
cth_find_clang_format()
131+
132+
Locates a required clang-format executable and exports its path to the parent scope.
133+
Terminates configuration with FATAL_ERROR if not found.
134+
135+
:post: CLANG_FORMAT_EXECUTABLE is set in PARENT_SCOPE with the full path to clang-format, or configuration terminates with FATAL_ERROR
82136
83137
.. seealso::
138+
See ``cth_find_opt_clang_format()`` for a variant that does not error if clang-format is not found.
84139
Use ``cth_add_clang_format_target()`` from cth_target_utilities to create a format target.
85140
86141
#]]
87142
function(cth_find_clang_format)
88-
cth_find_program(CLANG_FORMAT_EXECUTABLE clang-format)
143+
cth_find_opt_clang_format()
144+
145+
cth_assert_true(CLANG_FORMAT_EXECUTABLE REASON "clang-format not found")
89146

90-
message(STATUS "Found external clang-format: ${CLANG_FORMAT_EXECUTABLE}")
91-
92147
set(CLANG_FORMAT_EXECUTABLE ${CLANG_FORMAT_EXECUTABLE} PARENT_SCOPE)
93148
endfunction()

readme.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ Simple assertions that every language should have:
2828
- `cth_assert_[_not]_target` — assert a CMake target does (not) exists in the current scope.
2929
- `cth_assert_[_not]_empty` — assert a string value is (not) empty.
3030
- `cth_assert_program` — locate an external program (supports `find_program` args) and export `<PROG>_PROGRAM` to the parent scope (fails if not found).
31+
- `cth_assert_file` — assert that a particular file exists and is not a directory.
3132

3233
## cth_target_utilities
3334
To help you set up targets and dependencies quicker:

0 commit comments

Comments
 (0)