-
Notifications
You must be signed in to change notification settings - Fork 12
/
mo2_cpp.cmake
387 lines (327 loc) · 13 KB
/
mo2_cpp.cmake
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
cmake_minimum_required(VERSION 3.21)
if (POLICY CMP0144)
cmake_policy(SET CMP0144 NEW)
endif()
include(CMakeParseArguments)
include(${CMAKE_CURRENT_LIST_DIR}/mo2_utils.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/mo2_targets.cmake)
#! mo2_configure_target : do basic configuration for a MO2 C++ target
#
# this functions does many things:
# - glob relevant files and add them to the target
# - set many compile flags, definitions, etc.
# - add step to create translations (if not turned OFF)
#
# \param:SOURCE_TREE if set, a source_group will be created using TREE
# \param:WARNINGS enable all warnings, possible values are ON/All, OFF, or 1, 2, 3, 4
# for corresponding /W flags (ON is All) (default ON)
# \param:EXTERNAL_WARNINGS enable warnings for external libraries, possible values are
# the same as warnings, but ON is 3 (default 1)
# \param:PERMISSIVE permissive mode (default OFF)
# \param:BIGOBJ enable bigobj (default OFF)
# \param:CLI enable C++/CLR (default OFF)
# \param:TRANSLATIONS generate translations (default ON)
# \param:AUTOMOC automoc (and autouic, autoqrc), (default ON)
# \param:EXTRA_TRANSLATIONS extra translations to include (folder)
# \param:PUBLIC_DEPENDS adds PUBLIC dependencies to the target, see
# mo2_add_dependencies for information on what is available
# \param:PRIVATE_DEPENDS same a PUBLIC_DEPENDS, but link is PRIVATE instead of PUBLIC
#
function(mo2_configure_target TARGET)
cmake_parse_arguments(MO2 "SOURCE_TREE"
"WARNINGS;EXTERNAL_WARNINGS;PERMISSIVE;BIGOBJ;CLI;TRANSLATIONS;AUTOMOC"
"EXTRA_TRANSLATIONS;PUBLIC_DEPENDS;PRIVATE_DEPENDS"
${ARGN})
# configure parameters and compiler flags
mo2_set_if_not_defined(MO2_WARNINGS ON)
mo2_set_if_not_defined(MO2_EXTERNAL_WARNINGS 1)
mo2_set_if_not_defined(MO2_PERMISSIVE OFF)
mo2_set_if_not_defined(MO2_BIGOBJ OFF)
mo2_set_if_not_defined(MO2_CLI OFF)
mo2_set_if_not_defined(MO2_TRANSLATIONS ON)
mo2_set_if_not_defined(MO2_AUTOMOC ON)
mo2_set_if_not_defined(MO2_EXTRA_TRANSLATIONS "")
mo2_set_if_not_defined(MO2_PUBLIC_DEPENDS "")
mo2_set_if_not_defined(MO2_PRIVATE_DEPENDS "")
if (${MO2_AUTOMOC})
find_package(Qt6 COMPONENTS Widgets REQUIRED)
set_target_properties(${TARGET}
PROPERTIES AUTOMOC ON AUTOUIC ON AUTORCC ON)
endif()
target_compile_options(${TARGET}
PRIVATE "/MP"
$<$<CONFIG:RelWithDebInfo>:/O2>
)
set(CXX_STANDARD 20)
if (${MO2_CLI})
set(CXX_STANDARD 17)
endif()
set_target_properties(${TARGET} PROPERTIES
CXX_STANDARD ${CXX_STANDARD}
CXX_EXTENSIONS OFF)
# VS emits a warning for LTCG, at least for uibase, so maybe not required?
target_link_options(${TARGET}
PRIVATE
$<$<CONFIG:RelWithDebInfo>:/LTCG /INCREMENTAL:NO /OPT:REF /OPT:ICF>)
if (${MO2_WARNINGS} STREQUAL "ON")
set(MO2_WARNINGS "All")
endif()
if (${MO2_EXTERNAL_WARNINGS} STREQUAL "ON")
set(MO2_EXTERNAL_WARNINGS "3")
endif()
if(NOT (${MO2_WARNINGS} STREQUAL "OFF"))
string(TOLOWER ${MO2_WARNINGS} MO2_WARNINGS)
target_compile_options(${TARGET} PRIVATE "/W${MO2_WARNINGS}" "/wd4464")
# external warnings
if (${MO2_EXTERNAL_WARNINGS} STREQUAL "OFF")
target_compile_options(${TARGET}
PRIVATE "/external:anglebrackets" "/external:W0")
else()
string(TOLOWER ${MO2_EXTERNAL_WARNINGS} MO2_EXTERNAL_WARNINGS)
target_compile_options(${TARGET}
PRIVATE "/external:anglebrackets" "/external:W${MO2_EXTERNAL_WARNINGS}")
endif()
endif()
if(NOT ${MO2_PERMISSIVE})
target_compile_options(${TARGET} PRIVATE "/permissive-")
endif()
if(${MO2_BIGOBJ})
target_compile_options(${TARGET} PRIVATE "/bigobj")
endif()
# find source files
if(DEFINED AUTOGEN_BUILD_DIR)
set(UI_HEADERS_DIR ${AUTOGEN_BUILD_DIR})
else()
set(UI_HEADERS_DIR ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_autogen/include_RelWithDebInfo)
endif()
file(GLOB_RECURSE source_files CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
file(GLOB_RECURSE header_files CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
file(GLOB_RECURSE qrc_files CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.qrc)
file(GLOB_RECURSE rc_files CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.rc)
file(GLOB_RECURSE ui_files CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.ui)
file(GLOB_RECURSE ui_header_files CONFIGURE_DEPENDS ${UI_HEADERS_DIR}/*.h)
file(GLOB_RECURSE rule_files CONFIGURE_DEPENDS ${CMAKE_BINARY_DIR}/*.rule)
file(GLOB_RECURSE misc_files CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../*.natvis)
if (${MO2_SOURCE_TREE})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}
PREFIX src
FILES ${source_files} ${header_files})
else()
source_group(src REGULAR_EXPRESSION ".*\\.(h|cpp)")
endif()
source_group(ui REGULAR_EXPRESSION ".*\\.ui")
source_group(cmake FILES CMakeLists.txt)
source_group(autogen FILES ${rule_files} ${qm_files} ${ui_header_files})
source_group(autogen REGULAR_EXPRESSION ".*\\cmake_pch.*")
source_group(resources FILES ${rc_files} ${qrc_files})
if(${MO2_TRANSLATIONS})
mo2_add_translations(${TARGET}
INSTALL_RELEASE
SOURCES ${CMAKE_CURRENT_SOURCE_DIR} ${MO2_EXTRA_TRANSLATIONS})
endif()
target_sources(${TARGET}
PRIVATE
${source_files}
${header_files}
${ui_files}
${ui_header_files}
${qrc_files}
${rc_files}
${misc_files}
${qm_files})
execute_process(
COMMAND git log -1 --format=%h
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
target_compile_definitions(
${TARGET}
PRIVATE
_UNICODE
UNICODE
NOMINMAX
_CRT_SECURE_NO_WARNINGS
BOOST_CONFIG_SUPPRESS_OUTDATED_MESSAGE
_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING
QT_MESSAGELOGCONTEXT
GITID="${GIT_COMMIT_HASH}")
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/pch.h)
target_precompile_headers(${PROJECT_NAME}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/pch.h)
endif()
if(${MO2_CLI})
if (CMAKE_GENERATOR MATCHES "Visual Studio")
set_target_properties(${TARGET} PROPERTIES COMMON_LANGUAGE_RUNTIME "")
else()
# can this really happen?
set(COMPILE_FLAGS "${COMPILE_FLAGS} /clr")
string(REPLACE "/EHs" "/EHa" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
endif()
endif()
set_target_properties(${TARGET} PROPERTIES VS_STARTUP_PROJECT ${TARGET})
target_link_libraries(${TARGET} PRIVATE Version Dbghelp)
if (MO2_PUBLIC_DEPENDS)
mo2_add_dependencies(${TARGET} PUBLIC ${MO2_PUBLIC_DEPENDS})
endif()
if (MO2_PRIVATE_DEPENDS)
mo2_add_dependencies(${TARGET} PRIVATE ${MO2_PRIVATE_DEPENDS})
endif()
# set the VS startup project if not already set
get_property(startup_project DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT)
if (NOT startup_project)
set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${TARGET})
endif()
endfunction()
#! mo2_configure_tests : configure a target as a MO2 C++ tests
#
# this function creates a set of tests available in the ${TARET}_gtests variable
#
# \param:DEPENDS dependencies to link to AND add folder for ctest to look for DLLs,
# typically the library being tests
#
# extra arguments are given to mo2_configure_target, TRANSLATIONS and AUTOMOC are
# OFF by default
#
function(mo2_configure_tests TARGET)
mo2_configure_target(${TARGET} TRANSLATIONS OFF AUTOMOC OFF ${ARGN})
cmake_parse_arguments(MO2 "" "" "DEPENDS" ${ARGN})
set_target_properties(${TARGET} PROPERTIES MO2_TARGET_TYPE "tests")
find_package(GTest REQUIRED)
target_link_libraries(${TARGET} PRIVATE GTest::gtest GTest::gmock GTest::gtest_main)
mo2_add_dependencies(${TARGET} PRIVATE ${MO2_DEPENDS})
# gtest_discover_tests would be nice but it requires Qt DLL, uibase, etc., in the
# path, etc., and is not working right now
#
# there is an open CMake issue: https://gitlab.kitware.com/cmake/cmake/-/issues/21453
#
# gtest_discover_tests(${TARGET}
# WORKING_DIRECTORY ${MO2_INSTALL_PATH}/bin
# PROPERTIES
# VS_DEBUGGER_WORKING_DIRECTORY ${MO2_INSTALL_PATH}/bin
# )
#
gtest_add_tests(TARGET ${TARGET} TEST_LIST ${TARGET}_gtests)
set(${TARGET}_gtests ${${TARGET}_gtests} PARENT_SCOPE)
mo2_deploy_qt_for_tests(
TARGET ${TARGET}
BINARIES "$<FILTER:$<TARGET_RUNTIME_DLLS:${TARGET}>,EXCLUDE,^.*[/\\]Qt[^/\\]*[.]dll>")
set_tests_properties(${${TARGET}_gtests}
PROPERTIES
ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<JOIN:$<TARGET_RUNTIME_DLL_DIRS:${TARGET}>,\;>"
)
endfunction()
#! mo2_configure_uibase : configure the uibase target for MO2
#
# this function does mostly nothing except calling mo2_configure_target, but is useful
# to be consistent with other mo2_configure_XXX
#
function(mo2_configure_uibase TARGET)
if (NOT (${TARGET} STREQUAL "uibase"))
message(WARNING "mo2_configure_uibase() should only be used on the uibase target")
endif()
mo2_configure_target(${TARGET} ${ARGN})
set_target_properties(${TARGET} PROPERTIES MO2_TARGET_TYPE "uibase")
target_include_directories(${TARGET} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/game_features)
mo2_set_project_to_run_from_install(
${TARGET} EXECUTABLE ${CMAKE_INSTALL_PREFIX}/bin/ModOrganizer.exe)
endfunction()
#! mo2_configure_plugin : configure a target as a MO2 C++ plugin
#
# this function automatically set uibase as a dependency
#
# extra arguments are given to mo2_configure_target
#
function(mo2_configure_plugin TARGET)
mo2_configure_target(${TARGET} ${ARGN})
mo2_add_dependencies(${TARGET} PUBLIC uibase)
set_target_properties(${TARGET} PROPERTIES MO2_TARGET_TYPE "plugin")
mo2_set_project_to_run_from_install(
${TARGET} EXECUTABLE ${CMAKE_INSTALL_PREFIX}/bin/ModOrganizer.exe)
endfunction()
#! mo2_configure_library : configure a C++ library (NOT a plugin), can be a STATIC
# or SHARED library
#
# extra arguments are given to mo2_configure_target, TRANSLATIONS and AUTOMOC are
# OFF by default
#
function(mo2_configure_library TARGET)
mo2_configure_target(${TARGET} AUTOMOC OFF TRANSLATIONS OFF ${ARGN})
get_target_property(TARGET_TYPE ${TARGET} TYPE)
target_include_directories(${TARGET}
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
if (${TARGET_TYPE} STREQUAL "STATIC_LIBRARY")
set_target_properties(${TARGET} PROPERTIES MO2_TARGET_TYPE "library-static")
else()
mo2_set_project_to_run_from_install(
${TARGET} EXECUTABLE ${CMAKE_INSTALL_PREFIX}/bin/ModOrganizer.exe)
set_target_properties(${TARGET} PROPERTIES MO2_TARGET_TYPE "library-shared")
endif()
endfunction()
#! mo2_configure_executable : configure a target as MO2 C++ executable
#
# \param:ELEVATED set flag on the executable to run as elevated by default
#
# extra arguments are given to mo2_configure_target
#
function(mo2_configure_executable TARGET)
cmake_parse_arguments(MO2 "ELEVATED" "" "" ${ARGN})
mo2_configure_target(${TARGET} ${ARGN})
set_target_properties(${TARGET}
PROPERTIES WIN32_EXECUTABLE TRUE MO2_TARGET_TYPE "executable")
get_target_property(output_name ${TARGET} OUTPUT_NAME)
if("${output_name}" STREQUAL "output_name-NOTFOUND")
set(output_name ${TARGET})
endif()
mo2_set_project_to_run_from_install(
${TARGET} EXECUTABLE ${CMAKE_INSTALL_PREFIX}/bin/${output_name})
if (${MO2_ELEVATED})
# does not work with target_link_options, so keeping it that way for now... this
# is not a very used option anyway
set_target_properties(${TARGET} PROPERTIES LINK_FLAGS
"/MANIFESTUAC:\"level='requireAdministrator' uiAccess='false'\"")
endif()
endfunction()
#! mo2_install_target : set install for a MO2 target
#
# for this to work properly, the target must have been configured
#
# \param:FOLDER install the plugin as a folder, instead of a single DLL, ignore for
# other target types
# \param:INSTALLDIR installation directory, default is automatically deduced based on
# the target type, this parameter is ignored for plugins and static libraries
#
function(mo2_install_target TARGET)
cmake_parse_arguments(MO2 "FOLDER" "INSTALLDIR" "" ${ARGN})
get_target_property(MO2_TARGET_TYPE ${TARGET} MO2_TARGET_TYPE)
# core install: .lib, .dll or .exe, to the right folder
if (${MO2_TARGET_TYPE} STREQUAL "uibase")
mo2_set_if_not_defined(MO2_INSTALLDIR "bin")
install(TARGETS ${TARGET} RUNTIME DESTINATION ${MO2_INSTALLDIR})
install(TARGETS ${TARGET} ARCHIVE DESTINATION libs)
elseif (${MO2_TARGET_TYPE} STREQUAL "plugin")
if (${MO2_FOLDER})
install(TARGETS ${TARGET} RUNTIME DESTINATION bin/plugins/$<TARGET_FILE_BASE_NAME:${TARGET}>)
else()
install(TARGETS ${TARGET} RUNTIME DESTINATION bin/plugins)
endif()
install(TARGETS ${TARGET} ARCHIVE DESTINATION libs)
elseif (${MO2_TARGET_TYPE} STREQUAL "library-static")
install(TARGETS ${TARGET} ARCHIVE DESTINATION libs)
elseif (${MO2_TARGET_TYPE} STREQUAL "library-shared")
mo2_set_if_not_defined(MO2_INSTALLDIR "bin/dlls")
install(TARGETS ${TARGET} RUNTIME DESTINATION ${MO2_INSTALLDIR})
install(TARGETS ${TARGET} ARCHIVE DESTINATION libs)
elseif (${MO2_TARGET_TYPE} STREQUAL "executable")
mo2_set_if_not_defined(MO2_INSTALLDIR "bin")
install(TARGETS ${TARGET} RUNTIME DESTINATION ${MO2_INSTALLDIR})
else()
message(FATAL_ERROR "unknown MO2 target type for target '${TARGET}', did you forget using mo2_configure_XXX?")
endif()
# install PDB if possible
if (NOT (${MO2_TARGET_TYPE} STREQUAL "library-static"))
install(FILES $<TARGET_PDB_FILE:${TARGET}> DESTINATION pdb)
endif()
endfunction()