File: reproc.cmake

package info (click to toggle)
reproc 14.2.5-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 600 kB
  • sloc: ansic: 3,219; cpp: 749; makefile: 9
file content (408 lines) | stat: -rw-r--r-- 11,467 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
include(CheckCCompilerFlag)
include(CMakePackageConfigHelpers)
include(GenerateExportHeader)
include(GNUInstallDirs)

# Developer options

option(REPROC_DEVELOP "Enable all developer options" $ENV{REPROC_DEVELOP})
option(REPROC_TEST "Build tests" ${REPROC_DEVELOP})
option(REPROC_EXAMPLES "Build examples" ${REPROC_DEVELOP})
option(REPROC_WARNINGS "Enable compiler warnings" ${REPROC_DEVELOP})
option(REPROC_TIDY "Run clang-tidy when building" ${REPROC_DEVELOP})

option(
  REPROC_SANITIZERS
  "Build with sanitizers on configurations that support it"
  ${REPROC_DEVELOP}
)

option(
  REPROC_WARNINGS_AS_ERRORS
  "Add -Werror or equivalent to the compile flags and clang-tidy"
)

mark_as_advanced(
  REPROC_TIDY
  REPROC_SANITIZERS
  REPROC_WARNINGS_AS_ERRORS
)

# Installation options

option(REPROC_OBJECT_LIBRARIES "Build CMake object libraries" ${REPROC_DEVELOP})

if(NOT REPROC_OBJECT_LIBRARIES)
  set(REPROC_INSTALL_DEFAULT ON)
endif()

option(REPROC_INSTALL "Generate installation rules" ${REPROC_INSTALL_DEFAULT})
option(REPROC_INSTALL_PKGCONFIG "Install pkg-config files" ON)

set(
  REPROC_INSTALL_CMAKECONFIGDIR
  ${CMAKE_INSTALL_LIBDIR}/cmake
  CACHE STRING "CMake config files installation directory"
)

set(
  REPROC_INSTALL_PKGCONFIGDIR
  ${CMAKE_INSTALL_LIBDIR}/pkgconfig
  CACHE STRING "pkg-config files installation directory"
)

mark_as_advanced(
  REPROC_OBJECT_LIBRARIES
  REPROC_INSTALL
  REPROC_INSTALL_PKGCONFIG
  REPROC_INSTALL_CMAKECONFIGDIR
  REPROC_INSTALL_PKGCONFIGDIR
)

# Testing

if(REPROC_TEST)
  enable_testing()
endif()

# Build type

if(REPROC_DEVELOP AND NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
  set(CMAKE_BUILD_TYPE Debug CACHE STRING "Build type" FORCE)
  set_property(
    CACHE CMAKE_BUILD_TYPE
    PROPERTY STRINGS Debug Release MinSizeRel RelWithDebInfo
  )
endif()

# clang-tidy

if(REPROC_TIDY)
  find_program(REPROC_TIDY_PROGRAM clang-tidy)
  mark_as_advanced(REPROC_TIDY_PROGRAM)

  if(NOT REPROC_TIDY_PROGRAM)
    message(FATAL_ERROR "clang-tidy not found")
  endif()

  if(REPROC_WARNINGS_AS_ERRORS)
    set(REPROC_TIDY_PROGRAM ${REPROC_TIDY_PROGRAM} -warnings-as-errors=*)
  endif()
endif()

# Functions

function(reproc_common TARGET LANGUAGE NAME DIRECTORY)
  if(LANGUAGE STREQUAL C)
    set(STANDARD 99)
    target_compile_features(${TARGET} PUBLIC c_std_99)
  else()
    # clang-tidy uses the MSVC standard library instead of MinGW's standard
    # library so we have to use C++14 (because MSVC headers use C++14).
    if(MINGW AND REPROC_TIDY)
      set(STANDARD 14)
    else()
      set(STANDARD 11)
    endif()

    target_compile_features(${TARGET} PUBLIC cxx_std_11)
  endif()

  set_target_properties(${TARGET} PROPERTIES
    ${LANGUAGE}_STANDARD ${STANDARD}
    ${LANGUAGE}_STANDARD_REQUIRED ON
    ${LANGUAGE}_EXTENSIONS OFF
    OUTPUT_NAME "${NAME}"
    RUNTIME_OUTPUT_DIRECTORY "${DIRECTORY}"
    ARCHIVE_OUTPUT_DIRECTORY "${DIRECTORY}"
    LIBRARY_OUTPUT_DIRECTORY "${DIRECTORY}"
  )

  if(REPROC_TIDY AND REPROC_TIDY_PROGRAM)
    set_property(
      TARGET ${TARGET}
      # `REPROC_TIDY_PROGRAM` is a list so we surround it with quotes to pass it
      # as a single argument.
      PROPERTY ${LANGUAGE}_CLANG_TIDY "${REPROC_TIDY_PROGRAM}"
    )
  endif()

  # Common development flags (warnings + sanitizers + colors)

  if(REPROC_WARNINGS)
    if(MSVC)
      check_c_compiler_flag(/permissive- REPROC_HAVE_PERMISSIVE)

      target_compile_options(${TARGET} PRIVATE
        /nologo # Silence MSVC compiler version output.
        $<$<BOOL:${REPROC_WARNINGS_AS_ERRORS}>:/WX> # -Werror
        $<$<BOOL:${REPROC_HAVE_PERMISSIVE}>:/permissive->
      )

      if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.15.0)
        # CMake 3.15 does not add /W3 to the compiler flags by default anymore
        # so we add /W4 instead.
        target_compile_options(${TARGET} PRIVATE /W4)
      endif()

      if(LANGUAGE STREQUAL C)
        # Disable MSVC warnings that flag C99 features as non-standard.
        target_compile_options(${TARGET} PRIVATE /wd4204 /wd4221)
      endif()
    else()
      target_compile_options(${TARGET} PRIVATE
        -Wall
        -Wextra
        -pedantic
        -Wconversion
        -Wsign-conversion
        $<$<BOOL:${REPROC_WARNINGS_AS_ERRORS}>:-Werror>
        $<$<BOOL:${REPROC_WARNINGS_AS_ERRORS}>:-pedantic-errors>
      )

      if(LANGUAGE STREQUAL C OR CMAKE_CXX_COMPILER_ID MATCHES Clang)
        target_compile_options(${TARGET} PRIVATE -Wmissing-prototypes)
      endif()
    endif()

    if(WIN32)
      target_compile_definitions(${TARGET} PRIVATE _CRT_SECURE_NO_WARNINGS)
    endif()

    target_compile_options(${TARGET} PRIVATE
      $<$<${LANGUAGE}_COMPILER_ID:GNU>:-fdiagnostics-color>
      $<$<${LANGUAGE}_COMPILER_ID:Clang>:-fcolor-diagnostics>
    )
  endif()

  if(REPROC_SANITIZERS AND NOT MSVC AND NOT MINGW)
    if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.15.0)
      set_property(
        TARGET ${TARGET}
        PROPERTY MSVC_RUNTIME_LIBRARY MultiThreaded
      )
    endif()

    target_compile_options(${TARGET} PRIVATE
      -fsanitize=address,undefined
      -fno-omit-frame-pointer
    )

    target_link_libraries(${TARGET} PRIVATE -fsanitize=address,undefined)
  endif()
endfunction()

function(reproc_library TARGET LANGUAGE)
  if(REPROC_OBJECT_LIBRARIES)
    add_library(${TARGET} OBJECT)
  else()
    add_library(${TARGET})
  endif()

  reproc_common(${TARGET} ${LANGUAGE} "" lib)

  if(BUILD_SHARED_LIBS AND NOT REPROC_OBJECT_LIBRARIES)
    # Enable -fvisibility=hidden and -fvisibility-inlines-hidden.
    set_target_properties(${TARGET} PROPERTIES
      ${LANGUAGE}_VISIBILITY_PRESET hidden
      VISIBILITY_INLINES_HIDDEN true
    )

    # clang-tidy errors with: unknown argument: '-fno-keep-inline-dllexport'
    # when enabling `VISIBILITY_INLINES_HIDDEN` on MinGW so we disable it when
    # running clang-tidy on MinGW.
    if(MINGW AND REPROC_TIDY)
      set_property(TARGET ${TARGET} PROPERTY VISIBILITY_INLINES_HIDDEN false)
    endif()

    # Disable CMake's default export definition.
    set_property(TARGET ${TARGET} PROPERTY DEFINE_SYMBOL "")

    string(TOUPPER ${TARGET} TARGET_UPPER)
    string(REPLACE + X TARGET_SANITIZED ${TARGET_UPPER})

    target_compile_definitions(${TARGET} PRIVATE ${TARGET_SANITIZED}_BUILDING)
    if(WIN32)
      target_compile_definitions(${TARGET} PUBLIC ${TARGET_SANITIZED}_SHARED)
    endif()
  endif()

  # Make sure we follow the popular naming convention for shared libraries on
  # UNIX systems.
  set_target_properties(${TARGET} PROPERTIES
    VERSION ${PROJECT_VERSION}
    SOVERSION ${PROJECT_VERSION_MAJOR}
  )

  # Only use the headers from the repository when building. When installing we
  # want to use the install location of the headers (e.g. /usr/include) as the
  # include directory instead.
  target_include_directories(${TARGET} PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  )

  # Adapted from https://codingnest.com/basic-cmake-part-2/.
  # Each library is installed separately (with separate config files).

  if(REPROC_INSTALL)

    # Headers

    install(
      DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/
      DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
      COMPONENT ${TARGET}-development
    )

    # Library

    install(
      TARGETS ${TARGET}
      EXPORT ${TARGET}-targets
      RUNTIME
        DESTINATION ${CMAKE_INSTALL_BINDIR}
        COMPONENT ${TARGET}-runtime
      LIBRARY
        DESTINATION ${CMAKE_INSTALL_LIBDIR}
        COMPONENT ${TARGET}-runtime
        NAMELINK_COMPONENT ${TARGET}-development
      ARCHIVE
        DESTINATION ${CMAKE_INSTALL_LIBDIR}
        COMPONENT ${TARGET}-development
      INCLUDES
        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
    )

    if(NOT APPLE)
      set_property(
        TARGET ${TARGET}
        PROPERTY INSTALL_RPATH $ORIGIN
      )
    endif()

    # CMake config

    configure_package_config_file(
      ${CMAKE_CURRENT_SOURCE_DIR}/${TARGET}-config.cmake.in
      ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}-config.cmake
      INSTALL_DESTINATION ${REPROC_INSTALL_CMAKECONFIGDIR}/${TARGET}
    )

    write_basic_package_version_file(
      ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}-config-version.cmake
      COMPATIBILITY SameMajorVersion
    )

    install(
      FILES
        ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}-config.cmake
        ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}-config-version.cmake
      DESTINATION ${REPROC_INSTALL_CMAKECONFIGDIR}/${TARGET}
      COMPONENT ${TARGET}-development
    )

    install(
      EXPORT ${TARGET}-targets
      DESTINATION ${REPROC_INSTALL_CMAKECONFIGDIR}/${TARGET}
      COMPONENT ${TARGET}-development
    )

    # pkg-config

    if(REPROC_INSTALL_PKGCONFIG)
      configure_file(
        ${CMAKE_CURRENT_SOURCE_DIR}/${TARGET}.pc.in
        ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}.pc
        @ONLY
      )

      install(
        FILES ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}.pc
        DESTINATION ${REPROC_INSTALL_PKGCONFIGDIR}
        COMPONENT ${TARGET}-development
      )
    endif()
  endif()
endfunction()

function(reproc_test TARGET NAME LANGUAGE)
  if(NOT REPROC_TEST)
    return()
  endif()

  if(LANGUAGE STREQUAL C)
    set(EXTENSION c)
  else()
    set(EXTENSION cpp)
  endif()

  add_executable(${TARGET}-test-${NAME} test/${NAME}.${EXTENSION})

  reproc_common(${TARGET}-test-${NAME} ${LANGUAGE} ${NAME} test)
  target_link_libraries(${TARGET}-test-${NAME} PRIVATE ${TARGET})

  if(MINGW)
    target_compile_definitions(${TARGET}-test-${NAME} PRIVATE
      __USE_MINGW_ANSI_STDIO=1 # Add %zu on Mingw
    )
  endif()

  add_test(NAME ${TARGET}-test-${NAME} COMMAND ${TARGET}-test-${NAME})

  if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/resources/${NAME}.c)
    target_compile_definitions(${TARGET}-test-${NAME} PRIVATE
      RESOURCE_DIRECTORY="${CMAKE_CURRENT_BINARY_DIR}/resources"
    )

    if (NOT TARGET ${TARGET}-resource-${NAME})
      add_executable(${TARGET}-resource-${NAME} resources/${NAME}.c)
      reproc_common(${TARGET}-resource-${NAME} C ${NAME} resources)
    endif()

    # Make sure the test resource is available when running the test.
    add_dependencies(${TARGET}-test-${NAME} ${TARGET}-resource-${NAME})
  endif()
endfunction()

function(reproc_example TARGET NAME LANGUAGE)
  cmake_parse_arguments(OPT "" "" "ARGS;DEPENDS" ${ARGN})
  if(NOT REPROC_EXAMPLES)
    return()
  endif()

  if(LANGUAGE STREQUAL C)
    set(EXTENSION c)
  else()
    set(EXTENSION cpp)
  endif()

  add_executable(${TARGET}-example-${NAME} examples/${NAME}.${EXTENSION})

  reproc_common(${TARGET}-example-${NAME} ${LANGUAGE} ${NAME} examples)
  target_link_libraries(${TARGET}-example-${NAME} PRIVATE ${TARGET} ${OPT_DEPENDS})

  if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/resources/${NAME}.c)
    target_compile_definitions(${TARGET}-example-${NAME} PRIVATE
      RESOURCE_DIRECTORY="${CMAKE_CURRENT_BINARY_DIR}/resources"
    )

    if (NOT TARGET ${TARGET}-resource-${NAME})
      add_executable(${TARGET}-resource-${NAME} resources/${NAME}.c)
      reproc_common(${TARGET}-resource-${NAME} C ${NAME} resources)
    endif()

    # Make sure the example resource is available when running the example.
    add_dependencies(${TARGET}-example-${NAME} ${TARGET}-resource-${NAME})
  endif()

  if(REPROC_TEST)
    if(NOT DEFINED OPT_ARGS)
      set(OPT_ARGS cmake --help)
    endif()

    add_test(
      NAME ${TARGET}-example-${NAME}
      COMMAND ${TARGET}-example-${NAME} ${OPT_ARGS}
    )
  endif()
endfunction()