OSDN Git Service

remove redundant inclusions in KatieBUildMacros file
[kde/Katie.git] / cmake / modules / KatieBuildMacros.cmake
1 # Copyright (c) 2015-2020, Ivailo Monev, <xakepa10@gmail.com>
2 # Redistribution and use is allowed according to the terms of the BSD license.
3
4 set(KATIE_UIC "uic")
5 set(KATIE_RCC "rcc")
6 set(KATIE_MOC "bootstrap_moc")
7 set(KATIE_LRELEASE "lrelease")
8
9 include(CMakePushCheckState)
10 include(CheckStructHasMember)
11
12 # a macro to print a dev warning but only when the build type is Debug
13 macro(KATIE_WARNING MESSAGESTR)
14     if(CMAKE_BUILD_TYPE STREQUAL "Debug")
15         message(AUTHOR_WARNING "${MESSAGESTR} ${ARGN}")
16     endif()
17 endmacro()
18
19 # a function to check for C function/definition, works for external functions.
20 function(KATIE_CHECK_DEFINED FORDEFINITION FROMHEADER)
21     set(compileout "${CMAKE_BINARY_DIR}/${FORDEFINITION}.cpp")
22     configure_file(
23         "${CMAKE_SOURCE_DIR}/cmake/modules/katie_check_defined.cpp.cmake"
24         "${compileout}"
25         @ONLY
26     )
27     try_compile(${FORDEFINITION}_test
28         "${CMAKE_BINARY_DIR}"
29         "${compileout}"
30         COMPILE_DEFINITIONS ${ARGN}
31         OUTPUT_VARIABLE ${FORDEFINITION}_test_output
32     )
33     if(${FORDEFINITION}_test)
34         message(STATUS "Found ${FORDEFINITION} in: <${FROMHEADER}>")
35         set(HAVE_${FORDEFINITION} TRUE PARENT_SCOPE)
36     else()
37         message(STATUS "Could not find ${FORDEFINITION} in: <${FROMHEADER}>")
38         set(HAVE_${FORDEFINITION} FALSE PARENT_SCOPE)
39     endif()
40 endfunction()
41
42 # a macro to check for C function presence in header, if function is found a
43 # definition is added.
44 macro(KATIE_CHECK_FUNCTION FORFUNCTION FROMHEADER)
45     katie_check_defined("${FORFUNCTION}" "${FROMHEADER}" ${ARGN})
46
47     if(HAVE_${FORFUNCTION})
48         string(TOUPPER "${FORFUNCTION}" upperfunction)
49         add_definitions(-DQT_HAVE_${upperfunction})
50     endif()
51 endmacro()
52
53 # a function to check for C function with 64-bit offset alternative, sets
54 # QT_LARGEFILE_SUPPORT to FALSE if not available and does not perform
55 # additional checks if one fails
56 function(KATIE_CHECK_FUNCTION64 FORFUNCTION FROMHEADER)
57     if(QT_LARGEFILE_SUPPORT)
58         katie_check_defined("${FORFUNCTION}" "${FROMHEADER}" -D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE ${ARGN})
59
60         if(NOT HAVE_${FORFUNCTION})
61             set(QT_LARGEFILE_SUPPORT FALSE PARENT_SCOPE)
62         endif()
63     endif()
64 endfunction()
65
66 # a macro to check for C struct member presence in header, if member is found a
67 # definition is added.
68 function(KATIE_CHECK_STRUCT FORSTRUCT FORMEMBER FROMHEADER)
69     cmake_reset_check_state()
70     check_struct_has_member("struct ${FORSTRUCT}" "${FORMEMBER}" "${FROMHEADER}" HAVE_${FORSTRUCT}_${FORMEMBER})
71     cmake_pop_check_state()
72
73     if(HAVE_${FORSTRUCT}_${FORMEMBER})
74         string(TOUPPER "${FORSTRUCT}_${FORMEMBER}" upperstructmember)
75         add_definitions(-DQT_HAVE_${upperstructmember})
76     endif()
77 endfunction()
78
79 # a macro to write data to file, does nothing if the file exists and its
80 # content is the same as the data to be written
81 macro(KATIE_WRITE_FILE OUTFILE DATA)
82     if(NOT EXISTS "${OUTFILE}")
83         file(WRITE "${OUTFILE}" "${DATA}")
84     else()
85         file(READ "${OUTFILE}" OUTDATA)
86         if(NOT "${OUTDATA}" STREQUAL "${DATA}")
87             file(WRITE "${OUTFILE}" "${DATA}")
88         endif()
89     endif()
90 endmacro()
91
92 # a macro to create camel-case headers pointing to their lower-case alternative
93 # as well as meta header that includes all component headers
94 macro(KATIE_GENERATE_PUBLIC PUBLIC_INCLUDES SUBDIR)
95     foreach(pubheader ${PUBLIC_INCLUDES})
96         string(TOLOWER ${pubheader} pubname)
97         set(pubout "${CMAKE_BINARY_DIR}/include/${SUBDIR}/${pubheader}")
98         katie_write_file("${pubout}" "#include <${pubname}.h>\n")
99     endforeach()
100
101     file(GLOB PUBLIC_LIST "${CMAKE_BINARY_DIR}/include/${SUBDIR}/*.h")
102     set(metaout "${CMAKE_BINARY_DIR}/include/${SUBDIR}/${SUBDIR}")
103     set(metadata "#ifndef ${SUBDIR}_META_H\n#define ${SUBDIR}_META_H\n\n")
104     foreach(pubheader ${PUBLIC_LIST})
105         get_filename_component(pubname ${pubheader} NAME)
106         # qtest_gui.h is exception because it requires explicit gui component linkage
107         if(NOT "${pubname}" STREQUAL "qtest_gui.h")
108             set(metadata "${metadata}#include <${SUBDIR}/${pubname}>\n")
109         endif()
110     endforeach()
111     set(metadata "${metadata}\n#endif\n")
112     katie_write_file("${metaout}" "${metadata}")
113 endmacro()
114
115 # a macro to copy headers into specific directory based on their base names
116 # ultimately suitable for copy operation of their destination
117 macro(KATIE_GENERATE_MISC MISC_INCLUDES SUBDIR)
118     foreach(mischeader ${MISC_INCLUDES})
119         get_filename_component(headername ${mischeader} NAME)
120         if("${headername}" MATCHES "(_p.h)")
121             set(headout "${CMAKE_BINARY_DIR}/privateinclude/${SUBDIR}/${headername}")
122         else()
123             set(headout "${CMAKE_BINARY_DIR}/include/${SUBDIR}/${headername}")
124         endif()
125         configure_file("${mischeader}" "${headout}" COPYONLY)
126     endforeach(mischeader)
127 endmacro()
128
129 macro(KATIE_GENERATE_OBSOLETE OBSOLETE_INCLUDE SUBDIR REDIRECT)
130     set(pubout "${CMAKE_BINARY_DIR}/include/${SUBDIR}/${OBSOLETE_INCLUDE}")
131     katie_write_file("${pubout}" "#include <${SUBDIR}/${REDIRECT}>\n")
132 endmacro()
133
134 # a macro for creating pkgconfig files for major components
135 macro(KATIE_GENERATE_PACKAGE FORTARGET REQUIRES)
136     string(REPLACE "Kt" "Qt" PACKAGE_FAKE "${FORTARGET}")
137     set(PACKAGE_NAME ${FORTARGET})
138     set(PACKAGE_REQUIRES ${REQUIRES})
139     string(REPLACE "Kt" "" compname "${FORTARGET}")
140     string(TOUPPER ${compname} compname)
141     set(PACKAGE_FLAGS "-DQT_${compname}_LIB")
142     # adding the definitions to other components is simply redundant since
143     # all components require the core component
144     if("${FORTARGET}" STREQUAL "KtCore")
145         katie_string_wrap("${KATIE_DEFINITIONS}" KATIE_DEFINITIONS)
146         set(PACKAGE_FLAGS "${PACKAGE_FLAGS} ${KATIE_DEFINITIONS}")
147     endif()
148     configure_file(
149         "${CMAKE_SOURCE_DIR}/cmake/pkgconfig.cmake"
150         "${CMAKE_BINARY_DIR}/pkgconfig/${FORTARGET}.pc"
151     )
152     install(
153         FILES "${CMAKE_BINARY_DIR}/pkgconfig/${FORTARGET}.pc"
154         DESTINATION "${KATIE_PKGCONFIG_PATH}"
155         COMPONENT Devel
156     )
157 endmacro()
158
159 # a function to ensure that (1) the output string is not null so that when it
160 # is passed to another function/macro it does not complain about inproper
161 # number of arguments and (2) it joins the input which if quoted has semicolons
162 # in it (if it is a list) that the sub-command (e.g. gcc) can not handle
163 function(KATIE_STRING_WRAP INVAR OUTSTR)
164     string(STRIP "${INVAR}" instrtrimmed)
165     if("${instrtrimmed}" STREQUAL "")
166         set(${OUTSTR} " " PARENT_SCOPE)
167     else()
168         string(REPLACE ";" " " modstring "${INVAR}")
169         set(${OUTSTR} "${modstring}" PARENT_SCOPE)
170     endif()
171 endfunction()
172
173 # a function to convert string to list, opposite of katie_string_wrap()
174 function(KATIE_STRING_UNWRAP INSTR OUTLST)
175     string(STRIP "${INSTR}" instrtrimmed)
176     if("${instrtrimmed}" STREQUAL "")
177         set(${OUTLST} " " PARENT_SCOPE)
178     else()
179         string(REPLACE " " ";${ARGN}" modstring "${ARGN}${INSTR}")
180         set(${OUTLST} ${modstring} PARENT_SCOPE)
181     endif()
182 endfunction()
183
184 # a function to get the Git checkout hash and store it in a variable
185 function(KATIE_GIT_CHECKOUT OUTSTR)
186     find_program(git NAMES git)
187     if(EXISTS "${CMAKE_SOURCE_DIR}/.git" AND NOT git)
188         message(WARNING "Git was not found, unable to obtain checkout.\n")
189     else(EXISTS "${CMAKE_SOURCE_DIR}/.git")
190         execute_process(
191             COMMAND "${git}" rev-parse HEAD
192             WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
193             RESULT_VARIABLE git_result
194             ERROR_VARIABLE git_output
195             OUTPUT_VARIABLE git_output
196             OUTPUT_STRIP_TRAILING_WHITESPACE
197         )
198
199         if(NOT git_result STREQUAL 0)
200             message(WARNING "Git command failed, unable to obtain checkout:\n${git_output}")
201         else()
202             set(${OUTSTR} "${git_output}" PARENT_SCOPE)
203         endif()
204     endif()
205 endfunction()
206
207 # a macro to instruct katie_setup_target() which sources to exclude from the
208 # all-in-one source file
209 macro(KATIE_ALLINONE_EXCLUDE ARG1)
210     set_source_files_properties(${ARG1} ${ARGN} PROPERTIES ALLINONE_EXCLUDE TRUE)
211 endmacro()
212
213 # a function to create an array of source files for a target while taking into
214 # account all-in-one target build setting up proper dependency for the
215 # moc/uic/rcc generated resources
216 function(KATIE_SETUP_TARGET FORTARGET)
217     # this can be simpler if continue() was supported by old CMake versions
218     set(resourcesdep "${CMAKE_CURRENT_BINARY_DIR}/${FORTARGET}_resources.cpp")
219     katie_write_file("${resourcesdep}" "enum { CompilersWorkaroundAlaAutomoc = 1 };\n")
220     set(targetresources)
221     set(rscpath "${CMAKE_CURRENT_BINARY_DIR}/${FORTARGET}_resources")
222     include_directories("${rscpath}")
223     foreach(tmpres ${ARGN})
224         get_filename_component(resource "${tmpres}" ABSOLUTE)
225         get_filename_component(rscext "${resource}" EXT)
226         get_filename_component(rscname "${resource}" NAME_WE)
227         if("${rscext}" STREQUAL ".ui")
228             set(rscout "${rscpath}/ui_${rscname}.h")
229             set(targetresources ${targetresources} "${rscout}")
230             make_directory("${rscpath}")
231             add_custom_command(
232                 COMMAND "${CMAKE_BINARY_DIR}/exec.sh" "${CMAKE_BINARY_DIR}/bin/${KATIE_UIC}${KATIE_TOOLS_SUFFIX}" "${resource}" -o "${rscout}"
233                 DEPENDS "${KATIE_UIC}"
234                 OUTPUT "${rscout}"
235             )
236         elseif("${rscext}" STREQUAL ".qrc")
237             set(rscout "${rscpath}/qrc_${rscname}.cpp")
238             set(targetresources ${targetresources} "${rscout}")
239             make_directory("${rscpath}")
240             add_custom_command(
241                 COMMAND "${CMAKE_BINARY_DIR}/exec.sh" "${CMAKE_BINARY_DIR}/bin/${KATIE_RCC}${KATIE_TOOLS_SUFFIX}" "${resource}" -o "${rscout}" -name "${rscname}"
242                 DEPENDS "${KATIE_RCC}"
243                 OUTPUT "${rscout}"
244             )
245         elseif("${rscext}" MATCHES "(.h|.hpp|.cc|.cpp)")
246             file(READ "${resource}" rsccontent)
247             if("${rsccontent}" MATCHES "(Q_OBJECT|Q_OBJECT_FAKE|Q_GADGET)")
248                 set(rscout "${rscpath}/moc_${rscname}${rscext}")
249                 set(targetresources ${targetresources} "${rscout}")
250                 get_directory_property(dirdefs COMPILE_DEFINITIONS)
251                 get_directory_property(dirincs INCLUDE_DIRECTORIES)
252                 set(mocargs)
253                 # COMPILE_DEFINITIONS does not include undefine definitions
254                 foreach(ddef ${dirdefs})
255                     set(mocargs ${mocargs} -D${ddef})
256                 endforeach()
257                 foreach(incdir ${dirincs})
258                     set(mocargs ${mocargs} -I${incdir})
259                 endforeach()
260                 make_directory("${rscpath}")
261                 add_custom_command(
262                     COMMAND "${CMAKE_BINARY_DIR}/exec.sh" "${CMAKE_BINARY_DIR}/bin/${KATIE_MOC}" -nw "${resource}" -o "${rscout}" ${mocargs}
263                     DEPENDS "${KATIE_MOC}"
264                     OUTPUT "${rscout}"
265                 )
266             endif()
267         elseif("${rscext}" MATCHES ".ts")
268             make_directory("${CMAKE_CURRENT_BINARY_DIR}")
269             set(rscout "${CMAKE_CURRENT_BINARY_DIR}/${rscname}.qm")
270             add_custom_target(
271                 ${FORTARGET}_${rscname} ALL
272                 COMMAND "${CMAKE_BINARY_DIR}/exec.sh" "${CMAKE_BINARY_DIR}/bin/${KATIE_LRELEASE}${KATIE_TOOLS_SUFFIX}" "${resource}" -qm "${rscout}"
273                 DEPENDS "${KATIE_LRELEASE}"
274             )
275             set_source_files_properties("${rscout}" PROPERTIES GENERATED TRUE)
276             install(
277                 FILES "${rscout}"
278                 DESTINATION "${KATIE_TRANSLATIONS_PATH}"
279                 COMPONENT Runtime
280             )
281         endif()
282     endforeach()
283     set_property(SOURCE "${resourcesdep}" APPEND PROPERTY OBJECT_DEPENDS "${targetresources}")
284
285     if(NOT KATIE_ALLINONE)
286         set(filteredsources)
287         foreach(srcstring ${ARGN})
288             get_filename_component(srcext "${srcstring}" EXT)
289             if(NOT "${srcext}" MATCHES "(.qrc|.ui)")
290                 set(filteredsources ${filteredsources} "${srcstring}")
291             endif()
292         endforeach()
293         set(${FORTARGET}_SOURCES "${resourcesdep}" ${filteredsources} PARENT_SCOPE)
294     else()
295         set(allinonesource "${CMAKE_CURRENT_BINARY_DIR}/${FORTARGET}_allinone.cpp")
296         set(allinonedata)
297         set(excludesources)
298         foreach(srcstring ${ARGN})
299             get_filename_component(srcext "${srcstring}" EXT)
300             get_source_file_property(skip "${srcstring}" ALLINONE_EXCLUDE)
301             if(skip OR "${srcext}" STREQUAL ".c")
302                 katie_warning("Source is excluded: ${srcstring}")
303                 set(excludesources ${excludesources} "${srcstring}")
304             elseif(NOT "${srcext}" MATCHES "(.h|.qrc|.ui)")
305                 set(allinonedata "${allinonedata}#include \"${srcstring}\"\n")
306             endif()
307         endforeach()
308         katie_write_file("${allinonesource}" "${allinonedata}")
309         set(${FORTARGET}_SOURCES ${resourcesdep} "${allinonesource}" ${excludesources} PARENT_SCOPE)
310     endif()
311 endfunction()
312
313 # a macro to ensure that object targets are build with PIC if the target they
314 # are going to be used in (like $<TARGET_OBJECTS:foo>) is build with PIC or
315 # PIC has been enabled for all module/library/executable targets. in addition
316 # the macro will add the object include directories and definitions to the
317 # target properties
318 macro(KATIE_SETUP_OBJECT FORTARGET)
319     get_target_property(target_pic ${FORTARGET} POSITION_INDEPENDENT_CODE)
320     if(CMAKE_POSITION_INDEPENDENT_CODE OR target_pic)
321         foreach(objtarget ${ARGN})
322             set_target_properties(${objtarget} PROPERTIES
323                 POSITION_INDEPENDENT_CODE TRUE
324             )
325         endforeach()
326     endif()
327
328     foreach(objtarget ${ARGN})
329         get_target_property(object_definitions ${objtarget} COMPILE_DEFINITIONS)
330         get_target_property(object_includes ${objtarget} INCLUDE_DIRECTORIES)
331         if(object_definitions)
332             target_compile_definitions(${FORTARGET} PRIVATE ${object_definitions})
333         endif()
334         target_include_directories(${FORTARGET} PRIVATE ${object_includes})
335     endforeach()
336 endmacro()
337
338 # a macro to remove conditional code from headers which is only relevant to the
339 # process of building Katie itself
340 macro(KATIE_OPTIMIZE_HEADERS DIR)
341     find_program(unifdef NAMES unifdef)
342     if(unifdef)
343         install(
344             CODE "set(UNIFDEF_EXECUTABLE \"${unifdef}\")"
345             CODE "set(HEADERS_DIRECTORY \"${DIR}\")"
346             CODE "set(HEADERS_DEFINITIONS \"${ARGN}\")"
347             SCRIPT "${CMAKE_SOURCE_DIR}/cmake/modules/OptimizeHeaders.cmake"
348         )
349     else()
350         get_filename_component(basename "${DIR}" NAME)
351         message(WARNING "unifdef not installed, cannot optimize headers for: ${basename}")
352     endif()
353 endmacro()
354
355 # a macro to add tests easily by setting them up with the assumptions they make
356 macro(KATIE_TEST TESTNAME TESTSOURCES)
357     katie_setup_target(${TESTNAME} ${TESTSOURCES} ${ARGN})
358
359     add_executable(${TESTNAME} ${${TESTNAME}_SOURCES})
360
361     target_link_libraries(${TESTNAME} KtCore KtTest)
362     target_compile_definitions(
363         ${TESTNAME} PRIVATE
364         -DSRCDIR="${CMAKE_CURRENT_SOURCE_DIR}/"
365     )
366     set_target_properties(
367         ${TESTNAME} PROPERTIES
368         RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
369     )
370
371     add_test(
372         NAME ${TESTNAME}
373         COMMAND "${CMAKE_BINARY_DIR}/exec.sh" "${CMAKE_CURRENT_BINARY_DIR}/${TESTNAME}" -tickcounter
374     )
375 endmacro()
376
377 # a macro to add tests that require GUI easily by setting them up with the assumptions they make
378 macro(KATIE_GUI_TEST TESTNAME TESTSOURCES)
379     katie_test(${TESTNAME} ${TESTSOURCES} ${ARGN})
380
381     target_link_libraries(${TESTNAME} KtGui)
382     target_compile_definitions(
383         ${TESTNAME} PRIVATE
384         -DSRCDIR="${CMAKE_CURRENT_SOURCE_DIR}/"
385         -DQT_GUI_LIB
386     )
387 endmacro()