Skip to content

Commit

Permalink
Make EMBED_RESOURCE_FILES work with non-C23 compilers
Browse files Browse the repository at this point in the history
  • Loading branch information
rouault committed Oct 3, 2024
1 parent 29b2bfb commit 6d2a886
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 17 deletions.
6 changes: 1 addition & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -380,11 +380,7 @@ if (NOT BUILD_SHARED_LIBS AND IS_SHARP_EMBED_AVAILABLE_RES)
else()
set(DEFAULT_EMBED_RESOURCE_FILES OFF)
endif()
option(EMBED_RESOURCE_FILES "Whether resource files (limited to proj.db) should be embedded into the PROJ library (only available with a C23 compatible compiler)" ${DEFAULT_EMBED_RESOURCE_FILES})

if (EMBED_RESOURCE_FILES AND NOT IS_SHARP_EMBED_AVAILABLE_RES)
message(FATAL_ERROR "C23 #embed not available with this compiler")
endif()
option(EMBED_RESOURCE_FILES "Whether resource files (limited to proj.db) should be embedded into the PROJ library" ${DEFAULT_EMBED_RESOURCE_FILES})

option(USE_ONLY_EMBEDDED_RESOURCE_FILES "Whether embedded resource files (limited to proj.db) should be used (should nominally be used together with EMBED_RESOURCE_FILES=ON, otherwise this will result in non-functional builds)" OFF)

Expand Down
99 changes: 99 additions & 0 deletions cmake/FileEmbed.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Derived from https://gitlab.com/jhamberg/cmake-examples/-/blob/master/cmake/FileEmbed.cmake
# MIT licensed
# Copyright (c) 2022 Jonathan Hamberg

function(FileEmbedSetup)

if (NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/file_embed)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}file_embed)
endif ()

if (NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/file_embed/file_embed_empty.c)
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/file_embed/file_embed_empty.c "")
endif ()

add_library(file_embed ${CMAKE_CURRENT_BINARY_DIR}/file_embed/file_embed_empty.c)
target_include_directories(file_embed PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/file_embed)

endfunction()

function(FileEmbedAdd file)
FileEmbedGenerate(${file} var)
target_sources(file_embed PUBLIC ${var})

add_custom_command(
OUTPUT ${var}
COMMAND ${CMAKE_COMMAND}
-DRUN_FILE_EMBED_GENERATE=1
"-DFILE_EMBED_GENERATE_PATH=${file}"
-P ${PROJECT_SOURCE_DIR}/cmake/FileEmbed.cmake
MAIN_DEPENDENCY ${file}
)
endfunction()

function(FileEmbedGenerate file generated_c)

get_filename_component(base_filename ${file} NAME)
set(output_filename "${base_filename}.c")
string(MAKE_C_IDENTIFIER ${base_filename} c_name)
file(READ ${file} content HEX)

string(LENGTH "${content}" size)
math(EXPR size_mult_16 "${size} - (${size} % 16)")
string(SUBSTRING "${content}" 0 ${size_mult_16} content_mult_16)

string(REGEX REPLACE
"([A-Fa-f0-9][A-Fa-f0-9])\
([A-Fa-f0-9][A-Fa-f0-9])\
([A-Fa-f0-9][A-Fa-f0-9])\
([A-Fa-f0-9][A-Fa-f0-9])\
([A-Fa-f0-9][A-Fa-f0-9])\
([A-Fa-f0-9][A-Fa-f0-9])\
([A-Fa-f0-9][A-Fa-f0-9])\
([A-Fa-f0-9][A-Fa-f0-9])"
"0x\\1,0x\\2,0x\\3,0x\\4,0x\\5,0x\\6,0x\\7,0x\\8,\n" SEPARATED_HEX "${content_mult_16}")

set(SEPARATED_HEX_REMAINDER "")
if (NOT ${size_mult_16} EQUAL ${size})
string(SUBSTRING "${content}" ${size_mult_16} 16 content_remainder)
string(REGEX REPLACE "([A-Fa-f0-9][A-Fa-f0-9])" "0x\\1," SEPARATED_HEX_REMAINDER "${content_remainder}")
endif()

set(output_c "${SEPARATED_HEX}${SEPARATED_HEX_REMAINDER}")

set(output_c "
#include \"${c_name}.h\"
const uint8_t ${c_name}_data[] = {
${output_c}
}\;
unsigned ${c_name}_size = sizeof(${c_name}_data)\;
")

set(output_h "
#ifndef ${c_name}_H
#define ${c_name}_H
#include \"stdint.h\"
extern const uint8_t ${c_name}_data[]\;
extern unsigned ${c_name}_size\;
#endif // ${c_name}_H
")


if (NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/file_embed)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}file_embed)
endif ()


file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/file_embed/${c_name}.c
${output_c})

file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/file_embed/${c_name}.h
${output_h})

set(${generated_c} ${CMAKE_CURRENT_BINARY_DIR}/file_embed/${c_name}.c PARENT_SCOPE)

endfunction()

if (RUN_FILE_EMBED_GENERATE)
FileEmbedGenerate(${FILE_EMBED_GENERATE_PATH} var)
endif ()
25 changes: 15 additions & 10 deletions data/generate_proj_db.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ file(READ ${ALL_SQL_IN} CONTENTS)
string(REPLACE "\${PROJ_VERSION}" "${PROJ_VERSION}" CONTENTS_MOD "${CONTENTS}")
file(WRITE "${ALL_SQL_IN}" "${CONTENTS_MOD}")

set(generate_proj_db ON)

if(IS_DIRECTORY ${PROJ_DB_CACHE_DIR})
set(USE_PROJ_DB_CACHE_DIR TRUE)
set(PROJ_DB_SQL_MD5_FILE "${PROJ_DB_CACHE_DIR}/proj.db.sql.md5")
Expand All @@ -26,18 +28,21 @@ if(IS_DIRECTORY ${PROJ_DB_CACHE_DIR})
message(STATUS "Reusing cached proj.db from ${PROJ_DB_CACHE_DIR}")
get_filename_component(PROJ_DB_DIR "${PROJ_DB}" DIRECTORY)
file(COPY "${CACHED_PROJ_DB}" DESTINATION "${PROJ_DB_DIR}")
return()
file(TOUCH "${PROJ_DB}")
set(generate_proj_db OFF)
endif()
endif()

execute_process(COMMAND "${EXE_SQLITE3}" "${PROJ_DB}"
INPUT_FILE "${ALL_SQL_IN}"
RESULT_VARIABLE STATUS)
if (generate_proj_db)
execute_process(COMMAND "${EXE_SQLITE3}" "${PROJ_DB}"
INPUT_FILE "${ALL_SQL_IN}"
RESULT_VARIABLE STATUS)

if(STATUS AND NOT STATUS EQUAL 0)
message(FATAL_ERROR "Build of proj.db failed")
elseif(USE_PROJ_DB_CACHE_DIR)
message(STATUS "Saving cache: ${CACHED_PROJ_DB}")
file(COPY "${PROJ_DB}" DESTINATION "${PROJ_DB_CACHE_DIR}")
file(WRITE "${PROJ_DB_SQL_MD5_FILE}" "${PROJ_DB_SQL_MD5}\n")
if(STATUS AND NOT STATUS EQUAL 0)
message(FATAL_ERROR "Build of proj.db failed")
elseif(USE_PROJ_DB_CACHE_DIR)
message(STATUS "Saving cache: ${CACHED_PROJ_DB}")
file(COPY "${PROJ_DB}" DESTINATION "${PROJ_DB_CACHE_DIR}")
file(WRITE "${PROJ_DB_SQL_MD5_FILE}" "${PROJ_DB_SQL_MD5}\n")
endif()
endif()
8 changes: 8 additions & 0 deletions src/embedded_resources.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
#include "embedded_resources.h"

#if USE_SHARP_EMBED
const unsigned char *pj_get_embedded_proj_db(unsigned int *pnSize) {
static const unsigned char proj_db[] = {
#embed PROJ_DB
};
*pnSize = (unsigned int)sizeof(proj_db);
return proj_db;
}
#else
#include "file_embed/proj_db.h"
const unsigned char *pj_get_embedded_proj_db(unsigned int *pnSize) {
*pnSize = proj_db_size;
return proj_db_data;
}
#endif
19 changes: 17 additions & 2 deletions src/lib_proj.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -401,14 +401,29 @@ if("${CMAKE_C_COMPILER_ID}" STREQUAL "Intel")
PROPERTIES COMPILE_FLAGS ${FP_PRECISE})
endif()

if(EMBED_RESOURCE_FILES)
if (EMBED_RESOURCE_FILES AND NOT IS_SHARP_EMBED_AVAILABLE_RES)
set(EMBEDDED_PROJ_DB "file_embed/proj_db.c")
add_custom_command(
OUTPUT "${EMBEDDED_PROJ_DB}"
COMMAND ${CMAKE_COMMAND}
-DRUN_FILE_EMBED_GENERATE=1
"-DFILE_EMBED_GENERATE_PATH=${PROJECT_BINARY_DIR}/data/proj.db"
-P ${PROJECT_SOURCE_DIR}/cmake/FileEmbed.cmake
DEPENDS generate_proj_db "${PROJECT_BINARY_DIR}/data/proj.db"
)
target_sources(proj PRIVATE embedded_resources.c "${EMBEDDED_PROJ_DB}")
elseif(EMBED_RESOURCE_FILES AND IS_SHARP_EMBED_AVAILABLE_RES)
add_library(proj_resources OBJECT embedded_resources.c)
target_compile_definitions(proj_resources PRIVATE "PROJ_DB=\"${PROJECT_BINARY_DIR}/data/proj.db\"")
target_compile_definitions(proj_resources PRIVATE USE_SHARP_EMBED)
add_dependencies(proj_resources generate_proj_db)
option(PROJ_OBJECT_LIBRARIES_POSITION_INDEPENDENT_CODE "Set ON to produce -fPIC code" ${BUILD_SHARED_LIBS})
set_property(TARGET proj_resources PROPERTY POSITION_INDEPENDENT_CODE ${PROJ_OBJECT_LIBRARIES_POSITION_INDEPENDENT_CODE})
set_target_properties(proj_resources PROPERTIES C_STANDARD 23)
target_sources(proj PRIVATE $<TARGET_OBJECTS:proj_resources> memvfs.c)
target_sources(proj PRIVATE $<TARGET_OBJECTS:proj_resources>)
endif()
if (EMBED_RESOURCE_FILES)
target_sources(proj PRIVATE memvfs.c)
target_compile_definitions(proj PRIVATE EMBED_RESOURCE_FILES)
endif()
if (USE_ONLY_EMBEDDED_RESOURCE_FILES)
Expand Down

0 comments on commit 6d2a886

Please sign in to comment.