summaryrefslogtreecommitdiffstats
path: root/cmake_modules/UnityBuild.cmake
blob: 7c133f1257ea60e9626b40ef3c60969beec19ac2 (plain)
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
#
# Copyright (c) 2009-2012 Christoph Heindl
# Copyright (c) 2015 Csaba Kertész (csaba.kertesz@gmail.com)
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#    * Redistributions of source code must retain the above copyright
#       notice, this list of conditions and the following disclaimer.
#    * Redistributions in binary form must reproduce the above copyright
#       notice, this list of conditions and the following disclaimer in the
#       documentation and/or other materials provided with the distribution.
#    * Neither the name of the <organization> nor the
#       names of its contributors may be used to endorse or promote products
#       derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
#

MACRO (COMMIT_UNITY_FILE UNITY_FILE FILE_CONTENT)
  SET(DIRTY FALSE)
  # Check if the build file exists
  SET(OLD_FILE_CONTENT "")
  IF (NOT EXISTS ${${UNITY_FILE}} AND NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/${${UNITY_FILE}})
    SET(DIRTY TRUE)
  ELSE ()
    # Check the file content
    FILE(STRINGS ${${UNITY_FILE}} OLD_FILE_CONTENT)
    STRING(REPLACE ";" "" OLD_FILE_CONTENT "${OLD_FILE_CONTENT}")
    STRING(REPLACE "\n" "" NEW_CONTENT "${${FILE_CONTENT}}")
    STRING(COMPARE EQUAL "${OLD_FILE_CONTENT}" "${NEW_CONTENT}" EQUAL_CHECK)
    IF (NOT EQUAL_CHECK EQUAL 1)
      SET(DIRTY TRUE)
    ENDIF ()
  ENDIF ()
  IF (DIRTY MATCHES TRUE)
    MESSAGE(STATUS "Write Unity Build file: " ${${UNITY_FILE}})
    FILE(WRITE ${${UNITY_FILE}} "${${FILE_CONTENT}}")
  ENDIF ()
  # Create a dummy copy of the unity file to trigger CMake reconfigure if it is deleted.
  SET(UNITY_FILE_PATH "")
  SET(UNITY_FILE_NAME "")
  GET_FILENAME_COMPONENT(UNITY_FILE_PATH ${${UNITY_FILE}} PATH)
  GET_FILENAME_COMPONENT(UNITY_FILE_NAME ${${UNITY_FILE}} NAME)
  CONFIGURE_FILE(${${UNITY_FILE}} ${UNITY_FILE_PATH}/CMakeFiles/${UNITY_FILE_NAME}.dummy)
ENDMACRO ()

MACRO (ENABLE_UNITY_BUILD TARGET_NAME SOURCE_VARIABLE_NAME UNIT_SIZE EXTENSION)
  # Limit is zero based conversion of unit_size
  MATH(EXPR LIMIT ${UNIT_SIZE}-1)
  SET(FILES ${SOURCE_VARIABLE_NAME})
  # Effectivly ignore the source files from the build, but keep track them for changes.
  SET_SOURCE_FILES_PROPERTIES(${${FILES}} PROPERTIES HEADER_FILE_ONLY true)
  # Counts the number of source files up to the threshold
  SET(COUNTER ${LIMIT})
  # Have one or more unity build files
  SET(FILE_NUMBER 0)
  SET(BUILD_FILE "")
  SET(BUILD_FILE_CONTENT "")
  SET(UNITY_BUILD_FILES "")
  SET(_DEPS "")

  FOREACH (SOURCE_FILE ${${FILES}})
    IF (COUNTER EQUAL LIMIT)
      SET(_DEPS "")
      # Write the actual Unity Build file
      IF (NOT ${BUILD_FILE} STREQUAL "" AND NOT ${BUILD_FILE_CONTENT} STREQUAL "")
        COMMIT_UNITY_FILE(BUILD_FILE BUILD_FILE_CONTENT)
      ENDIF ()
      SET(UNITY_BUILD_FILES ${UNITY_BUILD_FILES} ${BUILD_FILE})
      # Set the variables for the current Unity Build file
      SET(BUILD_FILE ${CMAKE_CURRENT_BINARY_DIR}/unitybuild_${FILE_NUMBER}_${TARGET_NAME}.${EXTENSION})
      SET(BUILD_FILE_CONTENT "// Unity Build file generated by CMake\n")
      MATH(EXPR FILE_NUMBER ${FILE_NUMBER}+1)
      SET(COUNTER 0)
    ENDIF ()
    # Add source path to the file name if it is not there yet.
    SET(FINAL_SOURCE_FILE "")
    SET(SOURCE_PATH "")
    GET_FILENAME_COMPONENT(SOURCE_PATH ${SOURCE_FILE} PATH)
    IF (SOURCE_PATH STREQUAL "" OR NOT EXISTS ${SOURCE_FILE})
      SET(FINAL_SOURCE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE_FILE})
    ELSE ()
      SET(FINAL_SOURCE_FILE ${SOURCE_FILE})
    ENDIF ()
    # Treat only the existing files or moc_*.cpp files
    STRING(FIND ${SOURCE_FILE} "moc_" MOC_POS)
    IF (EXISTS ${FINAL_SOURCE_FILE} OR MOC_POS GREATER -1)
      # Add md5 hash of the source file (except moc files) to the build file content
      IF (MOC_POS LESS 0)
        SET(MD5_HASH "")
        FILE(MD5 ${FINAL_SOURCE_FILE} MD5_HASH)
        SET(BUILD_FILE_CONTENT "${BUILD_FILE_CONTENT}// md5: ${MD5_HASH}\n")
      ENDIF ()
      # Add the source file to the build file content
      IF (MOC_POS GREATER -1)
        SET(BUILD_FILE_CONTENT "${BUILD_FILE_CONTENT}#include <${SOURCE_FILE}>\n")
      ELSE ()
        SET(BUILD_FILE_CONTENT "${BUILD_FILE_CONTENT}#include <${FINAL_SOURCE_FILE}>\n")
      ENDIF ()
      # Add the source dependencies to the Unity Build file
      GET_SOURCE_FILE_PROPERTY(_FILE_DEPS ${SOURCE_FILE} OBJECT_DEPENDS)

      IF (_FILE_DEPS)
        SET(_DEPS ${_DEPS} ${_FILE_DEPS})
        SET_SOURCE_FILES_PROPERTIES(${BUILD_FILE} PROPERTIES OBJECT_DEPENDS "${_DEPS}")
      ENDIF()
      # Keep counting up to the threshold. Increment counter.
      MATH(EXPR COUNTER ${COUNTER}+1)
    ENDIF ()
  ENDFOREACH ()
  # Write out the last Unity Build file
  IF (NOT ${BUILD_FILE} STREQUAL "" AND NOT ${BUILD_FILE_CONTENT} STREQUAL "")
    COMMIT_UNITY_FILE(BUILD_FILE BUILD_FILE_CONTENT)
  ENDIF ()
  SET(UNITY_BUILD_FILES ${UNITY_BUILD_FILES} ${BUILD_FILE})
  SET(${SOURCE_VARIABLE_NAME} ${${SOURCE_VARIABLE_NAME}} ${UNITY_BUILD_FILES})
ENDMACRO ()

MACRO (UNITY_GENERATE_MOC TARGET_NAME SOURCES HEADERS)
  SET(NEW_SOURCES "")
  FOREACH (HEADER_FILE ${${HEADERS}})
    IF (NOT EXISTS ${HEADER_FILE})
      MESSAGE(FATAL_ERROR "Header file does not exist (mocing): ${HEADER_FILE}")
    ENDIF ()
    FILE(READ ${HEADER_FILE} FILE_CONTENT)
    STRING(FIND "${FILE_CONTENT}" "Q_OBJECT" QOBJECT_POS)
    STRING(FIND "${FILE_CONTENT}" "Q_SLOTS" QSLOTS_POS)
    STRING(FIND "${FILE_CONTENT}" "Q_SIGNALS" QSIGNALS_POS)
    STRING(FIND "${FILE_CONTENT}" "QObject" OBJECT_POS)
    STRING(FIND "${FILE_CONTENT}" "slots" SLOTS_POS)
    STRING(FIND "${FILE_CONTENT}" "signals" SIGNALS_POS)
    IF (QOBJECT_POS GREATER 0 OR OBJECT_POS GREATER 0 OR QSLOTS_POS GREATER 0 OR Q_SIGNALS GREATER 0 OR
        SLOTS_POS GREATER 0 OR SIGNALS GREATER 0)
      # Generate the moc filename
      GET_FILENAME_COMPONENT(HEADER_BASENAME ${HEADER_FILE} NAME_WE)
      SET(MOC_FILENAME "moc_${HEADER_BASENAME}.cpp")
      SET(NEW_SOURCES ${NEW_SOURCES} ; "${CMAKE_CURRENT_BINARY_DIR}/${MOC_FILENAME}")
      ADD_CUSTOM_COMMAND(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${MOC_FILENAME}"
                         DEPENDS ${HEADER_FILE}
                         COMMAND ${QT_MOC_EXECUTABLE} ${HEADER_FILE} -o "${CMAKE_CURRENT_BINARY_DIR}/${MOC_FILENAME}")
    ENDIF ()
  ENDFOREACH ()
  IF (NEW_SOURCES)
    SET_SOURCE_FILES_PROPERTIES(${NEW_SOURCES} PROPERTIES GENERATED TRUE)
    SET(${SOURCES} ${${SOURCES}} ; ${NEW_SOURCES})
  ENDIF ()
ENDMACRO ()