Setup and clear of string pool.
[SquirrelJME.git] / nanocoat / cmake / utils.cmake
blob509e4876d12aa4527e17c22c7011fb637d269734
1 # ---------------------------------------------------------------------------
2 # SquirrelJME
3 #     Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
4 # ---------------------------------------------------------------------------
5 # SquirrelJME is under the Mozilla Public License Version 2.0.
6 # See license.mkd for licensing and copyright information.
7 # ---------------------------------------------------------------------------
8 # DESCRIPTION: Defines the base project and the versioning info
10 # Echo commands accordingly
11 set(CMAKE_EXECUTE_PROCESS_COMMAND_ECHO STDERR)
13 # Where are we?
14 if(NOT DEFINED SQUIRRELJME_UTIL_CMAKE_WHERE)
15         set(SQUIRRELJME_UTIL_CMAKE_WHERE "${CMAKE_CURRENT_LIST_DIR}")
16 endif()
18 if(NOT DEFINED SQUIRRELJME_UTIL_CMAKE_WHERE)
19         set(SQUIRRELJME_UTIL_CMAKE_WHERE "${CMAKE_SOURCE_DIR}")
20 endif()
22 # The directory where the utilities should exist
23 get_filename_component(SQUIRRELJME_UTIL_SOURCE_DIR
24         "${SQUIRRELJME_UTIL_CMAKE_WHERE}/utils" ABSOLUTE)
25 get_filename_component(SQUIRRELJME_UTIL_DIR
26         "${CMAKE_BINARY_DIR}/utils" ABSOLUTE)
28 # Add macro to determine the path of a utility
29 macro(squirreljme_util var what)
30         set(${var}
31                 "${SQUIRRELJME_UTIL_DIR}/${what}${SQUIRRELJME_HOST_EXE_SUFFIX}")
32 endmacro()
34 # If we are on Windows, we do want to pass our generator
35 message(STATUS "CMake Generator Platform: ${CMAKE_GENERATOR_PLATFORM}")
36 if("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows")
37         unset(SQUIRRELJME_SWITCH_CMAKE_GENERATOR_PLATFORM_UNSET)
38         set(SQUIRRELJME_SWITCH_CMAKE_GENERATOR_PLATFORM_SET
39                 "-DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}")
40 else()
41         set(SQUIRRELJME_SWITCH_CMAKE_GENERATOR_PLATFORM_UNSET
42                 "--unset=CMAKE_GENERATOR_PLATFORM")
43         unset(SQUIRRELJME_SWITCH_CMAKE_GENERATOR_PLATFORM_SET)
44 endif()
46 # Need to cleanup any previous configuration run before building
47 if(EXISTS "${SQUIRRELJME_UTIL_DIR}/CMakeCache.txt" OR
48         (EXISTS "${SQUIRRELJME_UTIL_DIR}" AND
49                 IS_DIRECTORY "${SQUIRRELJME_UTIL_DIR}"))
50         file(REMOVE_RECURSE "${SQUIRRELJME_UTIL_DIR}/")
51 endif()
53 # Make sure the resultant utility directory exists
54 file(MAKE_DIRECTORY "${SQUIRRELJME_UTIL_DIR}")
56 # Try to find the host CMake as a first choice
57 find_program(SJME_FIRST_CMAKE "cmake" NO_DEFAULT_PATH)
58 if(NOT SJME_FIRST_CMAKE)
59         find_program(SJME_FIRST_CMAKE "cmake")
61         if(NOT SJME_FIRST_CMAKE)
62                 set(SJME_FIRST_CMAKE "${CMAKE_COMMAND}")
63         endif()
64 endif()
66 # Double check version
67 execute_process(COMMAND "${SJME_FIRST_CMAKE}" "-version"
68         OUTPUT_FILE "${CMAKE_BINARY_DIR}/first-cmake-version")
69 file(STRINGS "${CMAKE_BINARY_DIR}/first-cmake-version" SJME_FIRST_CMAKE_VER
70         LIMIT_COUNT 1)
71 string(TOLOWER "${SJME_FIRST_CMAKE_VER}" SJME_FIRST_CMAKE_VER)
72 string(REPLACE "cmake version " ""
73         SJME_FIRST_CMAKE_VER "${SJME_FIRST_CMAKE_VER}")
75 # If the CMake we found is too old, ignore it and use our current one
76 message(STATUS "CMake ${SJME_FIRST_CMAKE} is ${SJME_FIRST_CMAKE_VER}")
77 if("${SJME_FIRST_CMAKE_VER}" VERSION_LESS 3.0)
78         # Note
79         message(STATUS "Using ${CMAKE_COMMAND} as it is too old...")
81         # Just use our version
82         set(SJME_FIRST_CMAKE "${CMAKE_COMMAND}")
83 endif()
85 # Setup command to run
86 set(SJME_UTIL_CFG)
87 list(APPEND SJME_UTIL_CFG "${SJME_FIRST_CMAKE}")
88 list(APPEND SJME_UTIL_CFG "-E")
89 list(APPEND SJME_UTIL_CFG "env")
90 list(APPEND SJME_UTIL_CFG "--unset=CMAKE_TOOLCHAIN")
91 list(APPEND SJME_UTIL_CFG "--unset=CMAKE_TOOLCHAIN_FILE")
92 list(APPEND SJME_UTIL_CFG "--unset=CMAKE_SOURCE_ROOT")
93 list(APPEND SJME_UTIL_CFG "--unset=CMAKE_FRAMEWORK_PATH")
94 list(APPEND SJME_UTIL_CFG "--unset=CMAKE_INCLUDE_PATH")
95 list(APPEND SJME_UTIL_CFG "--unset=CMAKE_LIBRARY_PATH")
96 list(APPEND SJME_UTIL_CFG "--unset=CMAKE_PROGRAM_PATH")
97 list(APPEND SJME_UTIL_CFG "--unset=CMAKE_BUILD_TYPE")
98 list(APPEND SJME_UTIL_CFG "--unset=CMAKE_GENERATOR")
99 list(APPEND SJME_UTIL_CFG "--unset=CMAKE_GENERATOR_INSTANCE")
100 list(APPEND SJME_UTIL_CFG ${SQUIRRELJME_SWITCH_CMAKE_GENERATOR_PLATFORM_UNSET})
101 list(APPEND SJME_UTIL_CFG "--unset=CMAKE_GENERATOR_TOOLSET")
102 list(APPEND SJME_UTIL_CFG "--unset=CMAKE_C_COMPILER_LAUNCHER")
103 list(APPEND SJME_UTIL_CFG "--unset=CMAKE_C_LINKER_LAUNCHER")
104 list(APPEND SJME_UTIL_CFG "--unset=CC")
105 list(APPEND SJME_UTIL_CFG "--unset=CXX")
106 list(APPEND SJME_UTIL_CFG "--unset=CFLAGS")
107 list(APPEND SJME_UTIL_CFG "--unset=CXXFLAGS")
108 list(APPEND SJME_UTIL_CFG "--unset=LDFLAGS")
110 # Target CMake Command
111 list(APPEND SJME_UTIL_CFG "${SJME_FIRST_CMAKE}")
112 list(APPEND SJME_UTIL_CFG "-DCMAKE_BUILD_TYPE=Debug")
113 list(APPEND SJME_UTIL_CFG "-DCMAKE_SYSTEM_NAME=${CMAKE_HOST_SYSTEM_NAME}")
114 list(APPEND SJME_UTIL_CFG
115         "-DCMAKE_SYSTEM_PROCESSOR=${CMAKE_HOST_SYSTEM_PROCESSOR}")
116 list(APPEND SJME_UTIL_CFG ${SQUIRRELJME_SWITCH_CMAKE_GENERATOR_PLATFORM_SET})
118 if("${CMAKE_VERSION}" VERSION_GREATER_EQUAL "3.13" AND
119         "${SJME_FIRST_CMAKE_VER}"  VERSION_GREATER_EQUAL "3.13")
120         list(APPEND SJME_UTIL_CFG "-S" "${SQUIRRELJME_UTIL_SOURCE_DIR}")
121         list(APPEND SJME_UTIL_CFG "-B" "${SQUIRRELJME_UTIL_DIR}")
122 else()
123         list(APPEND SJME_UTIL_CFG "${SQUIRRELJME_UTIL_SOURCE_DIR}")
124 endif()
126 # Note
127 message(STATUS "Bootstrapping utils into "
128         "${SQUIRRELJME_UTIL_DIR}...")
129 message(STATUS "Current generator is ${CMAKE_GENERATOR}...")
131 # Divider
132 message(STATUS "CONFIGURE: -------------------------------------------------")
134 # Run Configuration
135 execute_process(
136         COMMAND ${SJME_UTIL_CFG}
137         WORKING_DIRECTORY "${SQUIRRELJME_UTIL_DIR}"
138         RESULT_VARIABLE SJME_UTIL_CFG_RESULT)
140 # Configure Failed?
141 if(NOT SJME_UTIL_CFG_RESULT EQUAL 0)
142         message(FATAL_ERROR "Configure failed with: ${SJME_UTIL_CFG_RESULT}")
143 endif()
145 # Divider
146 message(STATUS "BUILD: -----------------------------------------------------")
148 # Run build step
149 execute_process(
150         COMMAND "${SJME_FIRST_CMAKE}"
151                 "--build" "${SQUIRRELJME_UTIL_DIR}"
152         RESULT_VARIABLE SJME_UTIL_BLD_RESULT
153         WORKING_DIRECTORY "${SQUIRRELJME_UTIL_DIR}")
155 # Build Failed?
156 if(NOT SJME_UTIL_BLD_RESULT EQUAL 0)
157         message(FATAL_ERROR "Build failed with: ${SJME_UTIL_BLD_RESULT}")
158 endif()
160 # Divider
161 message(STATUS "PREFIX/SUFFIX: ---------------------------------------------")
163 # Determine executable suffix
164 if(EXISTS "${SQUIRRELJME_UTIL_DIR}/suffix")
165         file(STRINGS "${SQUIRRELJME_UTIL_DIR}/suffix"
166                 SQUIRRELJME_HOST_EXE_SUFFIX)
167         message(DEBUG "Host executable suffix is "
168                 "'${SQUIRRELJME_HOST_EXE_SUFFIX}'.")
169 endif()
171 # Determine dynamic library prefix
172 if(EXISTS "${SQUIRRELJME_UTIL_DIR}/dylibprefix")
173         file(STRINGS "${SQUIRRELJME_UTIL_DIR}/dylibprefix"
174                 SQUIRRELJME_HOST_DYLIB_PREFIX)
175         message(DEBUG "Host library prefix is "
176                 "'${SQUIRRELJME_HOST_DYLIB_PREFIX}'.")
177 endif()
179 # Determine dynamic library suffix
180 if(EXISTS "${SQUIRRELJME_UTIL_DIR}/dylibsuffix")
181         file(STRINGS "${SQUIRRELJME_UTIL_DIR}/dylibsuffix"
182                 SQUIRRELJME_HOST_DYLIB_SUFFIX)
183         message(DEBUG "Host library suffix is "
184                 "'${SQUIRRELJME_HOST_DYLIB_SUFFIX}'.")
185 endif()
187 # Divider
188 message(STATUS "SIMPLE CHECK: ----------------------------------------------")
190 # Try running simple utility to make sure it compiled under the host
191 squirreljme_util(SJME_UTIL_SIMPLE simple)
192 execute_process(COMMAND "${SJME_UTIL_SIMPLE}"
193         RESULT_VARIABLE SJME_UTIL_CHK_RESULT
194         WORKING_DIRECTORY "${SQUIRRELJME_UTIL_DIR}")
196 # Make sure it is actually valid
197 if(NOT SJME_UTIL_CHK_RESULT EQUAL 0)
198         message(FATAL_ERROR "Simple run failed with: ${SJME_UTIL_CHK_RESULT}")
199 endif()
201 # Divider
202 message(STATUS "------------------------------------------------------------")
204 # ----------------------------------------------------------------------------
206 # Checks if a given file is out of date according to a checksum
207 function(squirreljme_check_file_checksum upToDateVar
208         inputFile outputPath)
209         # Get hash of input file
210         file(SHA1 "${inputFile}" cacheHash)
212         # Get last checksum, if any
213         if(EXISTS "${outputPath}.checksum")
214                 file(STRINGS "${outputPath}.checksum"
215                         cacheHashLast)
216         else()
217                 set(cacheHashLast "")
218         endif()
220         # Is the checksum out of date?
221         if(NOT EXISTS "${outputPath}.checksum" OR
222                 NOT EXISTS "${outputPath}" OR
223                 NOT "${cacheHash}" STREQUAL "${cacheHashLast}")
224                 set(${upToDateVar} 0 PARENT_SCOPE)
225         else()
226                 set(${upToDateVar} 1 PARENT_SCOPE)
227         endif()
228 endfunction()
230 # Writes the checksum of the input file to the output
231 function(squirreljme_write_file_checksum inputFile
232         outputPath)
233         # Get hash of input file
234         file(SHA1 "${inputFile}" cacheHash)
236         # Store checksum
237         file(WRITE "${outputPath}.checksum"
238                 "${cacheHash}")
239 endfunction()
241 # Decodes the given file
242 function(squirreljme_decode_file how
243         inputPath outputPath)
244         # Should be HEX or BASE64
245         if(NOT how STREQUAL "HEX" AND
246                 NOT how STREQUAL "BASE64")
247                 message(FATAL_ERROR "squirreljme_decode_file() takes "
248                         "either HEX or BASE64")
249         endif()
251         # Where is the decoder?
252         squirreljme_util(decodeExePath decode)
254         # Run the command
255         execute_process(COMMAND "${decodeExePath}" "${how}"
256                 INPUT_FILE "${inputPath}"
257                 OUTPUT_FILE "${outputPath}"
258                 RESULT_VARIABLE conversionExitCode
259                 TIMEOUT 16)
261         # Failed
262         if(conversionExitCode)
263                 message(FATAL_ERROR
264                         "Conversion failed: ${conversionExitCode}.")
265         endif()
266 endfunction()
268 # Decodes a directory of encoded files
269 function(squirreljme_decode_dir inputDir outputDir)
270         # Decode all files accordingly
271         file(GLOB inFiles
272                 "${inputDir}/*.__hex"
273                 "${inputDir}/*.__mime")
274         foreach(inFile ${inFiles})
275                 # Determine the base name of the file
276                 get_filename_component(baseName
277                         "${inFile}" NAME)
279                 # Is this Hex or MIME?
280                 string(FIND "${baseName}" ".__hex"
281                         isHexFile)
283                 # Remove extension from it
284                 string(REPLACE ".__hex" ""
285                         baseName
286                         "${baseName}")
287                 string(REPLACE ".__mime" ""
288                         baseName
289                         "${baseName}")
291                 # Make sure the target directory exists first
292                 file(MAKE_DIRECTORY "${outputDir}")
294                 # Determine input and output
295                 get_filename_component(inFileAbs
296                         "${inFile}" ABSOLUTE)
297                 get_filename_component(outFileAbsPath
298                         "${outputDir}/${baseName}" ABSOLUTE)
300                 # Check if file is up to date
301                 squirreljme_check_file_checksum(upToDate
302                         "${inFileAbs}" "${outFileAbsPath}")
304                 # Does decoding need to be rerun?
305                 if(NOT upToDate)
306                         # Run decoding sequence
307                         message(STATUS
308                                 "Decoding ${inFileAbs} to "
309                                 "${outFileAbsPath}...")
310                         file(REMOVE "${outFileAbsPath}")
311                         if(isHexFile LESS 0)
312                                 squirreljme_decode_file(BASE64
313                                         "${inFileAbs}" "${outFileAbsPath}")
314                         else()
315                                 squirreljme_decode_file(HEX
316                                         "${inFileAbs}" "${outFileAbsPath}")
317                         endif()
319                         # Store checksum
320                         squirreljme_write_file_checksum(
321                                 "${inFileAbs}" "${outFileAbsPath}")
322                 else()
323                         message(STATUS
324                                 "File ${outFileAbsPath} already decoded...")
325                 endif()
326         endforeach()
327 endfunction()
329 # Sourceize a single file
330 function(squirreljme_sourceize_file inputPath
331         outputCPath outputHPath)
332         # Get the base name of the input file
333         get_filename_component(inputPathBaseName
334                 "${inputPath}" NAME)
336         # Where is the encoder?
337         squirreljme_util(sourceizeExePath sourceize)
339         # Run the command
340         execute_process(COMMAND "${sourceizeExePath}"
341                         "${inputPathBaseName}" "C"
342                 INPUT_FILE "${inputPath}"
343                 OUTPUT_FILE "${outputCPath}"
344                 RESULT_VARIABLE sourceizeExitCode
345                 TIMEOUT 16)
346         execute_process(COMMAND "${sourceizeExePath}"
347                 "${inputPathBaseName}" "H"
348                 INPUT_FILE "${inputPath}"
349                 OUTPUT_FILE "${outputHPath}"
350                 RESULT_VARIABLE sourceizeExitCode
351                 TIMEOUT 16)
353         # Failed
354         if(sourceizeExitCode)
355                 message(FATAL_ERROR
356                         "Sourceize failed: ${sourceizeExitCode}.")
357         endif()
358 endfunction()
360 # Sourceize an entire directory
361 function(squirreljme_sourceize_dir inputDir outputDir)
362         # Encode all file accordingly
363         file(GLOB inFiles "${inputDir}/*")
364         foreach(inFile ${inFiles})
365                 # Determine the base name of the file
366                 get_filename_component(baseName
367                         "${inFile}" NAME)
369                 # Make sure the target directory exists first
370                 file(MAKE_DIRECTORY "${outputDir}")
372                 # Determine input and output
373                 get_filename_component(inFileAbs
374                         "${inFile}" ABSOLUTE)
375                 get_filename_component(outFileAbsPath
376                         "${outputDir}/${baseName}" ABSOLUTE)
378                 # Check if source file is up to date
379                 squirreljme_check_file_checksum(upToDate
380                         "${inFileAbs}" "${outFileAbsPath}.c")
381                 if(upToDate)
382                         # Do the same for the header file
383                         squirreljme_check_file_checksum(upToDate
384                                 "${inFileAbs}" "${outFileAbsPath}.h")
385                 endif()
387                 # Does decoding need to be rerun?
388                 if(NOT upToDate)
389                         # Run decoding sequence
390                         message(STATUS
391                                 "Sourceizing ${inFileAbs} to "
392                                 "${outFileAbsPath}.[ch]...")
393                         file(REMOVE "${outFileAbsPath}.c")
394                         file(REMOVE "${outFileAbsPath}.h")
395                         squirreljme_sourceize_file("${inFileAbs}"
396                                 "${outFileAbsPath}.c" "${outFileAbsPath}.h")
398                         # Store checksum
399                         squirreljme_write_file_checksum(
400                                 "${inFileAbs}" "${outFileAbsPath}.c")
401                         squirreljme_write_file_checksum(
402                                 "${inFileAbs}" "${outFileAbsPath}.h")
403                 else()
404                         message(STATUS
405                                 "File ${outFileAbsPath}.c already sourceized...")
406                 endif()
407         endforeach()
408 endfunction()
410 # Set variable for dynamic library import
411 macro(squirreljme_library_set var target)
412         if(MSVC)
413                 set(${var}
414                         "${SQUIRRELJME_UTIL_DIR}/${SQUIRRELJME_HOST_DYLIB_PREFIX}${target}.lib")
415         else()
416                 set(${var}
417                         "${SQUIRRELJME_UTIL_DIR}/${SQUIRRELJME_HOST_DYLIB_PREFIX}${target}${SQUIRRELJME_HOST_DYLIB_SUFFIX}")
418         endif()
419 endmacro()