1
- cmake_minimum_required (VERSION 3.8...3.26 )
1
+ cmake_minimum_required (VERSION 3.8...3.28 )
2
2
3
3
# Fallback for using newer policies on CMake <3.12.
4
- if (${CMAKE_VERSION} VERSION_LESS 3.12)
4
+ if (${CMAKE_VERSION} VERSION_LESS 3.12)
5
5
cmake_policy (VERSION ${CMAKE_MAJOR_VERSION} .${CMAKE_MINOR_VERSION} )
6
- endif ()
6
+ endif ()
7
7
8
8
# Determine if fmt is built as a subproject (using add_subdirectory)
9
9
# or if it is the master project.
@@ -36,6 +36,12 @@ function(enable_module target)
36
36
endif ()
37
37
endfunction ()
38
38
39
+ set (FMT_USE_CMAKE_MODULES FALSE )
40
+ if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.28 AND
41
+ CMAKE_GENERATOR STREQUAL "Ninja" )
42
+ set (FMT_USE_CMAKE_MODULES TRUE )
43
+ endif ()
44
+
39
45
# Adds a library compiled with C++20 module support.
40
46
# `enabled` is a CMake variables that specifies if modules are enabled.
41
47
# If modules are disabled `add_module_library` falls back to creating a
@@ -53,6 +59,7 @@ function(add_module_library name)
53
59
if (NOT ${${AML_IF} })
54
60
# Create a non-modular library.
55
61
target_sources (${name} PRIVATE ${AML_FALLBACK} )
62
+ set_target_properties (${name} PROPERTIES CXX_SCAN_FOR_MODULES OFF )
56
63
return ()
57
64
endif ()
58
65
@@ -62,48 +69,53 @@ function(add_module_library name)
62
69
target_compile_options (${name} PUBLIC -fmodules-ts)
63
70
endif ()
64
71
65
- # `std` is affected by CMake options and may be higher than C++20.
66
- get_target_property (std ${name} CXX_STANDARD)
67
-
68
- if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
69
- set (pcms)
70
- foreach (src ${sources} )
71
- get_filename_component (pcm ${src} NAME_WE )
72
- set (pcm ${pcm} .pcm)
73
-
74
- # Propagate -fmodule-file=*.pcm to targets that link with this library.
75
- target_compile_options (
76
- ${name} PUBLIC -fmodule-file=${CMAKE_CURRENT_BINARY_DIR} /${pcm} )
77
-
78
- # Use an absolute path to prevent target_link_libraries prepending -l
79
- # to it.
80
- set (pcms ${pcms} ${CMAKE_CURRENT_BINARY_DIR} /${pcm} )
81
- add_custom_command (
82
- OUTPUT ${pcm}
83
- COMMAND ${CMAKE_CXX_COMPILER}
84
- -std=c++${std} -x c++-module --precompile -c
85
- -o ${pcm} ${CMAKE_CURRENT_SOURCE_DIR} /${src}
86
- "-I$<JOIN:$<TARGET_PROPERTY:${name} ,INCLUDE_DIRECTORIES>,;-I>"
87
- # Required by the -I generator expression above.
88
- COMMAND_EXPAND_LISTS
89
- DEPENDS ${src} )
90
- endforeach ()
91
-
92
- # Add .pcm files as sources to make sure they are built before the library.
93
- set (sources )
94
- foreach (pcm ${pcms} )
95
- get_filename_component (pcm_we ${pcm} NAME_WE )
96
- set (obj ${pcm_we} .o)
97
- # Use an absolute path to prevent target_link_libraries prepending -l.
98
- set (sources ${sources} ${pcm} ${CMAKE_CURRENT_BINARY_DIR} /${obj} )
99
- add_custom_command (
100
- OUTPUT ${obj}
101
- COMMAND ${CMAKE_CXX_COMPILER} $<TARGET_PROPERTY:${name} ,COMPILE_OPTIONS>
102
- -c -o ${obj} ${pcm}
103
- DEPENDS ${pcm} )
104
- endforeach ()
105
- endif ()
106
- target_sources (${name} PRIVATE ${sources} )
72
+ if (FMT_USE_CMAKE_MODULES)
73
+ target_sources (${name} PUBLIC FILE_SET fmt TYPE CXX_MODULES
74
+ FILES ${sources} )
75
+ else ()
76
+ # `std` is affected by CMake options and may be higher than C++20.
77
+ get_target_property (std ${name} CXX_STANDARD)
78
+
79
+ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
80
+ set (pcms)
81
+ foreach (src ${sources} )
82
+ get_filename_component (pcm ${src} NAME_WE )
83
+ set (pcm ${pcm} .pcm)
84
+
85
+ # Propagate -fmodule-file=*.pcm to targets that link with this library.
86
+ target_compile_options (
87
+ ${name} PUBLIC -fmodule-file=${CMAKE_CURRENT_BINARY_DIR} /${pcm} )
88
+
89
+ # Use an absolute path to prevent target_link_libraries prepending -l
90
+ # to it.
91
+ set (pcms ${pcms} ${CMAKE_CURRENT_BINARY_DIR} /${pcm} )
92
+ add_custom_command (
93
+ OUTPUT ${pcm}
94
+ COMMAND ${CMAKE_CXX_COMPILER}
95
+ -std=c++${std} -x c++-module --precompile -c
96
+ -o ${pcm} ${CMAKE_CURRENT_SOURCE_DIR} /${src}
97
+ "-I$<JOIN:$<TARGET_PROPERTY:${name} ,INCLUDE_DIRECTORIES>,;-I>"
98
+ # Required by the -I generator expression above.
99
+ COMMAND_EXPAND_LISTS
100
+ DEPENDS ${src} )
101
+ endforeach ()
102
+
103
+ # Add .pcm files as sources to make sure they are built before the library.
104
+ set (sources )
105
+ foreach (pcm ${pcms} )
106
+ get_filename_component (pcm_we ${pcm} NAME_WE )
107
+ set (obj ${pcm_we} .o)
108
+ # Use an absolute path to prevent target_link_libraries prepending -l.
109
+ set (sources ${sources} ${pcm} ${CMAKE_CURRENT_BINARY_DIR} /${obj} )
110
+ add_custom_command (
111
+ OUTPUT ${obj}
112
+ COMMAND ${CMAKE_CXX_COMPILER} $<TARGET_PROPERTY:${name} ,COMPILE_OPTIONS>
113
+ -c -o ${obj} ${pcm}
114
+ DEPENDS ${pcm} )
115
+ endforeach ()
116
+ endif ()
117
+ target_sources (${name} PRIVATE ${sources} )
118
+ endif ()
107
119
endfunction ()
108
120
109
121
include (CMakeParseArguments)
@@ -150,9 +162,10 @@ option(FMT_INSTALL "Generate the install target." ON)
150
162
option (FMT_TEST "Generate the test target." ${FMT_MASTER_PROJECT} )
151
163
option (FMT_FUZZ "Generate the fuzz target." OFF )
152
164
option (FMT_CUDA_TEST "Generate the cuda-test target." OFF )
153
- option (FMT_OS "Include core requiring OS (Windows/Posix) " ON )
165
+ option (FMT_OS "Include OS-specific APIs. " ON )
154
166
option (FMT_MODULE "Build a module instead of a traditional library." OFF )
155
167
option (FMT_SYSTEM_HEADERS "Expose headers with marking them as system." OFF )
168
+ option (FMT_UNICODE "Enable Unicode support." ON )
156
169
157
170
if (FMT_TEST AND FMT_MODULE)
158
171
# The tests require {fmt} to be compiled as traditional library
@@ -162,23 +175,23 @@ set(FMT_SYSTEM_HEADERS_ATTRIBUTE "")
162
175
if (FMT_SYSTEM_HEADERS)
163
176
set (FMT_SYSTEM_HEADERS_ATTRIBUTE SYSTEM )
164
177
endif ()
165
- if (CMAKE_SYSTEM_NAME STREQUAL "MSDOS" )
178
+ if (CMAKE_SYSTEM_NAME STREQUAL "MSDOS" )
166
179
set (FMT_TEST OFF )
167
180
message (STATUS "MSDOS is incompatible with gtest" )
168
- endif ()
181
+ endif ()
169
182
170
- # Get version from core .h
171
- file (READ include /fmt/core .h core_h )
172
- if (NOT core_h MATCHES "FMT_VERSION ([0-9]+)([0-9][0-9])([0-9][0-9])" )
173
- message (FATAL_ERROR "Cannot get FMT_VERSION from core .h." )
183
+ # Get version from base .h
184
+ file (READ include /fmt/base .h base_h )
185
+ if (NOT base_h MATCHES "FMT_VERSION ([0-9]+)([0-9][0-9])([0-9][0-9])" )
186
+ message (FATAL_ERROR "Cannot get FMT_VERSION from base .h." )
174
187
endif ()
175
188
# Use math to skip leading zeros if any.
176
189
math (EXPR CPACK_PACKAGE_VERSION_MAJOR ${CMAKE_MATCH_1} )
177
190
math (EXPR CPACK_PACKAGE_VERSION_MINOR ${CMAKE_MATCH_2} )
178
191
math (EXPR CPACK_PACKAGE_VERSION_PATCH ${CMAKE_MATCH_3} )
179
192
join(FMT_VERSION ${CPACK_PACKAGE_VERSION_MAJOR} .${CPACK_PACKAGE_VERSION_MINOR} .
180
193
${CPACK_PACKAGE_VERSION_PATCH} )
181
- message (STATUS "Version : ${FMT_VERSION} " )
194
+ message (STATUS "{fmt} version : ${FMT_VERSION} " )
182
195
183
196
message (STATUS "Build type: ${CMAKE_BUILD_TYPE} " )
184
197
@@ -225,7 +238,13 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
225
238
endif ()
226
239
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0)
227
240
set (PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wshift-overflow=2
228
- -Wnull-dereference -Wduplicated-cond)
241
+ -Wduplicated-cond)
242
+ # Workaround for GCC regression
243
+ # [12/13/14/15 regression] New (since gcc 12) false positive null-dereference in vector.resize
244
+ # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108860
245
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.0)
246
+ set (PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wnull-dereference)
247
+ endif ()
229
248
endif ()
230
249
set (WERROR_FLAG -Werror)
231
250
endif ()
@@ -274,20 +293,21 @@ function(add_headers VAR)
274
293
endfunction ()
275
294
276
295
# Define the fmt library, its includes and the needed defines.
277
- add_headers(FMT_HEADERS args.h chrono.h color.h compile.h core.h format.h
296
+ add_headers(FMT_HEADERS args.h base.h chrono.h color.h compile.h core.h format.h
278
297
format-inl.h os.h ostream.h printf.h ranges.h std.h
279
298
xchar.h)
280
299
set (FMT_SOURCES src/format.cc)
281
- if (FMT_OS)
282
- set (FMT_SOURCES ${FMT_SOURCES} src/os.cc)
283
- endif ()
284
300
285
301
add_module_library(fmt src/fmt.cc FALLBACK
286
- ${FMT_SOURCES} ${FMT_HEADERS} README.rst ChangeLog.rst
302
+ ${FMT_SOURCES} ${FMT_HEADERS} README.md ChangeLog.md
287
303
IF FMT_MODULE)
288
304
add_library (fmt::fmt ALIAS fmt)
289
305
if (FMT_MODULE)
290
306
enable_module(fmt)
307
+ elseif (FMT_OS)
308
+ target_sources (fmt PRIVATE src/os.cc)
309
+ else ()
310
+ target_compile_definitions (fmt PRIVATE FMT_OS=0)
291
311
endif ()
292
312
293
313
if (FMT_WERROR)
@@ -303,7 +323,7 @@ else ()
303
323
message (WARNING "Feature cxx_std_11 is unknown for the CXX compiler" )
304
324
endif ()
305
325
306
- target_include_directories (fmt ${FMT_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC
326
+ target_include_directories (fmt ${FMT_SYSTEM_HEADERS_ATTRIBUTE} BEFORE PUBLIC
307
327
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR} /include >
308
328
$<INSTALL_INTERFACE:${FMT_INC_DIR} >)
309
329
@@ -312,7 +332,15 @@ set(FMT_DEBUG_POSTFIX d CACHE STRING "Debug library postfix.")
312
332
set_target_properties (fmt PROPERTIES
313
333
VERSION ${FMT_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}
314
334
PUBLIC_HEADER "${FMT_HEADERS} "
315
- DEBUG_POSTFIX "${FMT_DEBUG_POSTFIX} " )
335
+ DEBUG_POSTFIX "${FMT_DEBUG_POSTFIX} "
336
+
337
+ # Workaround for Visual Studio 2017:
338
+ # Ensure the .pdb is created with the same name and in the same directory
339
+ # as the .lib. Newer VS versions already do this by default, but there is no
340
+ # harm in setting it for those too. Ignored by other generators.
341
+ COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR} "
342
+ COMPILE_PDB_NAME "fmt"
343
+ COMPILE_PDB_NAME_DEBUG "fmt${FMT_DEBUG_POSTFIX} " )
316
344
317
345
# Set FMT_LIB_NAME for pkg-config fmt.pc. We cannot use the OUTPUT_NAME target
318
346
# property because it's not set by default.
@@ -326,15 +354,26 @@ if (BUILD_SHARED_LIBS)
326
354
endif ()
327
355
if (FMT_SAFE_DURATION_CAST)
328
356
target_compile_definitions (fmt PUBLIC FMT_SAFE_DURATION_CAST)
329
- endif ()
357
+ endif ()
330
358
331
359
add_library (fmt-header-only INTERFACE )
332
360
add_library (fmt::fmt-header-only ALIAS fmt-header-only)
333
361
362
+ if (NOT MSVC )
363
+ # Unicode is always supported on compilers other than MSVC.
364
+ elseif (FMT_UNICODE)
365
+ # Unicode support requires compiling with /utf-8.
366
+ target_compile_options (fmt PUBLIC $<$<AND :$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:MSVC >>:/utf-8>)
367
+ target_compile_options (fmt-header-only INTERFACE $<$<AND :$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:MSVC >>:/utf-8>)
368
+ else ()
369
+ target_compile_definitions (fmt PUBLIC FMT_UNICODE=0)
370
+ endif ()
371
+
334
372
target_compile_definitions (fmt-header-only INTERFACE FMT_HEADER_ONLY=1)
335
373
target_compile_features (fmt-header-only INTERFACE cxx_std_11)
336
374
337
- target_include_directories (fmt-header-only ${FMT_SYSTEM_HEADERS_ATTRIBUTE} INTERFACE
375
+ target_include_directories (fmt-header-only
376
+ ${FMT_SYSTEM_HEADERS_ATTRIBUTE} BEFORE INTERFACE
338
377
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR} /include >
339
378
$<INSTALL_INTERFACE:${FMT_INC_DIR} >)
340
379
@@ -379,30 +418,77 @@ if (FMT_INSTALL)
379
418
380
419
set (INSTALL_TARGETS fmt fmt-header-only)
381
420
421
+ set (INSTALL_FILE_SET)
422
+ if (FMT_USE_CMAKE_MODULES)
423
+ set (INSTALL_FILE_SET FILE_SET fmt DESTINATION "${FMT_INC_DIR} /fmt" )
424
+ endif ()
425
+
382
426
# Install the library and headers.
383
- install (TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name}
427
+ install (TARGETS ${INSTALL_TARGETS}
428
+ COMPONENT fmt-core
429
+ EXPORT ${targets_export_name}
384
430
LIBRARY DESTINATION ${FMT_LIB_DIR}
385
431
ARCHIVE DESTINATION ${FMT_LIB_DIR}
386
432
PUBLIC_HEADER DESTINATION "${FMT_INC_DIR} /fmt"
387
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} )
433
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
434
+ ${INSTALL_FILE_SET} )
388
435
389
436
# Use a namespace because CMake provides better diagnostics for namespaced
390
437
# imported targets.
391
438
export (TARGETS ${INSTALL_TARGETS} NAMESPACE fmt::
392
439
FILE ${PROJECT_BINARY_DIR} /${targets_export_name} .cmake)
393
440
394
441
# Install version, config and target files.
395
- install (
396
- FILES ${project_config} ${version_config }
397
- DESTINATION ${FMT_CMAKE_DIR} )
442
+ install (FILES ${project_config} ${version_config}
443
+ DESTINATION ${FMT_CMAKE_DIR }
444
+ COMPONENT fmt-core )
398
445
install (EXPORT ${targets_export_name} DESTINATION ${FMT_CMAKE_DIR}
399
- NAMESPACE fmt::)
446
+ NAMESPACE fmt::
447
+ COMPONENT fmt-core)
400
448
401
- install (FILES "${pkgconfig} " DESTINATION "${FMT_PKGCONFIG_DIR} " )
449
+ install (FILES "${pkgconfig} " DESTINATION "${FMT_PKGCONFIG_DIR} "
450
+ COMPONENT fmt-core)
402
451
endif ()
403
452
453
+ function (add_doc_target)
454
+ find_program (DOXYGEN doxygen
455
+ PATHS "$ENV{ProgramFiles} /doxygen/bin"
456
+ "$ENV{ProgramFiles\( x86\) }/doxygen/bin" )
457
+ if (NOT DOXYGEN)
458
+ message (STATUS "Target 'doc' disabled because doxygen not found" )
459
+ return ()
460
+ endif ()
461
+
462
+ find_program (MKDOCS mkdocs)
463
+ if (NOT MKDOCS)
464
+ message (STATUS "Target 'doc' disabled because mkdocs not found" )
465
+ return ()
466
+ endif ()
467
+
468
+ set (sources )
469
+ foreach (source api.md index.md syntax.md get -started.md fmt.css fmt.js)
470
+ set (sources ${sources} doc /${source} )
471
+ endforeach ()
472
+
473
+ add_custom_target (
474
+ doc
475
+ COMMAND
476
+ ${CMAKE_COMMAND}
477
+ -E env PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR} /support/python
478
+ ${MKDOCS} build -f ${CMAKE_CURRENT_SOURCE_DIR} /support/mkdocs.yml
479
+ # MkDocs requires the site dir to be outside of the doc dir.
480
+ --site-dir ${CMAKE_CURRENT_BINARY_DIR} /doc -html
481
+ --no -directory -urls
482
+ SOURCES ${sources} )
483
+
484
+ include (GNUInstallDirs)
485
+ install (DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} /doc -html/
486
+ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR} /doc /fmt
487
+ COMPONENT fmt-doc OPTIONAL )
488
+ endfunction ()
489
+
404
490
if (FMT_DOC)
405
- add_subdirectory ( doc )
491
+ add_doc_target( )
406
492
endif ()
407
493
408
494
if (FMT_TEST)
@@ -432,13 +518,12 @@ if (FMT_MASTER_PROJECT AND EXISTS ${gitignore})
432
518
string (REPLACE "*" ".*" line "${line} " )
433
519
set (ignored_files ${ignored_files} "${line} $" "${line} /" )
434
520
endforeach ()
435
- set (ignored_files ${ignored_files}
436
- /.git /breathe /format-benchmark sphinx/ .buildinfo .doctrees)
521
+ set (ignored_files ${ignored_files} /.git /build /doxyxml .vagrant)
437
522
438
523
set (CPACK_SOURCE_GENERATOR ZIP)
439
524
set (CPACK_SOURCE_IGNORE_FILES ${ignored_files} )
440
525
set (CPACK_SOURCE_PACKAGE_FILE_NAME fmt-${FMT_VERSION} )
441
526
set (CPACK_PACKAGE_NAME fmt)
442
- set (CPACK_RESOURCE_FILE_README ${PROJECT_SOURCE_DIR} /README.rst )
527
+ set (CPACK_RESOURCE_FILE_README ${PROJECT_SOURCE_DIR} /README.md )
443
528
include (CPack)
444
529
endif ()
0 commit comments