summaryrefslogtreecommitdiff
path: root/cmake/Modules/Glib.cmake
diff options
context:
space:
mode:
Diffstat (limited to 'cmake/Modules/Glib.cmake')
-rw-r--r--cmake/Modules/Glib.cmake315
1 files changed, 315 insertions, 0 deletions
diff --git a/cmake/Modules/Glib.cmake b/cmake/Modules/Glib.cmake
new file mode 100644
index 0000000..0e5ab61
--- /dev/null
+++ b/cmake/Modules/Glib.cmake
@@ -0,0 +1,315 @@
+# SPDX-FileCopyrightText: 2025 Felix Morgner <felix.morgner@gmail.com>
+# SPDX-License-Identifier: LGPL-2.1-only
+
+include_guard()
+
+# Dependencies
+
+find_program(G_IR_COMPILER_BIN NAMES "g-ir-compiler" REQUIRED)
+find_program(G_IR_SCANNER_BIN NAMES "g-ir-scanner" REQUIRED)
+find_program(GLIB_COMPILE_RESOURCES NAMES "glib-compile-resources" REQUIRED)
+find_program(GLIB_COMPILE_SCHEMAS_BIN NAMES "glib-compile-schemas" REQUIRED)
+find_program(GLIB_MKENUMS_BIN NAMES "glib-mkenums" REQUIRED)
+
+# Functions
+
+function(glib_generate_gir TARGET)
+ if(NOT BUILD_SHARED_LIBS)
+ message(STATUS "Glib: skipping GIR generation for static library target '${TARGET}'")
+ return()
+ endif()
+
+ set(SINGLE_VALUE_ARGS
+ "NAMESPACE"
+ "OUTPUT"
+ "VERSION"
+ )
+ set(MULTI_VALUE_ARGS
+ "DEPENDENCIES"
+ "SOURCES"
+ )
+ cmake_parse_arguments(
+ PARSE_ARGV 1
+ ""
+ "${OPTIONS}"
+ "${SINGLE_VALUE_ARGS}"
+ "${MULTI_VALUE_ARGS}"
+ )
+
+ if(NOT TARGET "${TARGET}")
+ message(FATAL_ERROR "Glib: Target '${TARGET}' does not exist")
+ endif()
+
+ if(NOT _NAMESPACE)
+ set(_NAMESPACE "${PROJECT_NAME}")
+ message(WARNING "Glib: defaulting to namespace ${_NAMESPACE}")
+ endif()
+
+ if(NOT _OUTPUT_DIR)
+ get_target_property(_OUTPUT_DIR "${TARGET}" BINARY_DIR)
+ endif()
+
+ if(NOT _VERSION)
+ set(_VERSION "${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}")
+ message(WARNING "Glib: defaulting to version ${_VERSION}")
+ endif()
+
+ if(NOT _DEPENDENCIES)
+ message(FATAL_ERROR "Glib: no dependencies specified")
+ endif()
+
+ if(NOT _SOURCES)
+ get_target_property(SOURCES "${TARGET}" SOURCES)
+ get_target_property(HEADERS "${TARGET}" HEADER_SET)
+ set(_SOURCES ${HEADERS} ${SOURCES})
+ endif()
+
+ get_target_property(TARGET_OUTPUT_NAME "${TARGET}" OUTPUT_NAME)
+ set(_OUTPUT_FILE "${_OUTPUT_DIR}/$<CONFIG>/${_NAMESPACE}-${_VERSION}")
+
+ add_custom_command(TARGET "${TARGET}"
+ POST_BUILD
+ BYPRODUCTS
+ "${_OUTPUT_FILE}.gir"
+ "${_OUTPUT_FILE}.typelib"
+ COMMENT "Generating GIR file for ${TARGET}"
+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ COMMAND "${G_IR_SCANNER_BIN}"
+ ARGS
+ "--quiet"
+ "--warn-all"
+ "--namespace=${_NAMESPACE}"
+ "--nsversion=${_VERSION}"
+ "--library=$<TARGET_FILE_BASE_NAME:${TARGET}>"
+ "--library-path=$<TARGET_FILE_DIR:${TARGET}>"
+ "$<LIST:TRANSFORM,$<TARGET_PROPERTY:${TARGET},INTERFACE_INCLUDE_DIRECTORIES>,PREPEND,-I>"
+ "$<LIST:TRANSFORM,$<LIST:TRANSFORM,${_DEPENDENCIES},TOLOWER>,PREPEND,--pkg=>"
+ "$<LIST:TRANSFORM,${_DEPENDENCIES},PREPEND,--include=>"
+ "--output=${_OUTPUT_FILE}.gir"
+ ${_SOURCES}
+ COMMAND "${G_IR_COMPILER_BIN}"
+ "--output=${_OUTPUT_FILE}.typelib"
+ "${_OUTPUT_FILE}.gir"
+ COMMAND_EXPAND_LISTS
+ VERBATIM
+ )
+
+ set(${_NAMESPACE}_GIR_FILE "${_OUTPUT_FILE}.gir" PARENT_SCOPE)
+ set(${_NAMESPACE}_TYPELIB_FILE "${_OUTPUT_FILE}.typelib" PARENT_SCOPE)
+endfunction()
+
+
+function(glib_add_resources TARGET)
+ set(SINGLE_VALUE_ARGS "NAME" "PREFIX" "WORKING_DIRECTORY")
+ set(MULTI_VALUE_ARGS "CSS_FILES" "XML_FILES")
+ cmake_parse_arguments(
+ PARSE_ARGV 1
+ ""
+ "${OPTIONS}"
+ "${SINGLE_VALUE_ARGS}"
+ "${MULTI_VALUE_ARGS}"
+ )
+
+ # Sanity Checks
+
+ if(NOT TARGET "${TARGET}")
+ message(FATAL_ERROR "Glib: Target '${TARGET}' does not exist")
+ endif()
+
+ if(NOT _NAME)
+ set(_NAME "${TARGET}")
+ endif()
+
+ if(NOT _PREFIX)
+ message(FATAL_ERROR "Glib: Resource prefix not defined")
+ endif()
+
+ if(NOT _WORKING_DIRECTORY)
+ set(_WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
+ endif()
+
+ # File Names
+
+ set(GLIB_RESOURCE_C_FILE "${CMAKE_CURRENT_BINARY_DIR}/${_NAME}.gresource.c")
+ set(GLIB_RESOURCE_MANIFEST "${CMAKE_CURRENT_BINARY_DIR}/${_NAME}.gresource.xml")
+
+ # Manifest File
+
+ foreach(XML_FILE IN LISTS _XML_FILES)
+ string(APPEND GLIB_RESOURCE_FILES " <file compressed=\"true\" preprocess=\"xml-stripblanks\">${XML_FILE}</file>\n")
+ endforeach()
+
+ foreach(CSS_FILE IN LISTS _CSS_FILES)
+ string(APPEND GLIB_RESOURCE_FILES " <file compressed=\"true\">${CSS_FILE}</file>\n")
+ endforeach()
+
+ string(STRIP "${GLIB_RESOURCE_FILES}" GLIB_RESOURCE_FILES)
+ set(GLIB_RESOURCE_PREFIX "${_PREFIX}")
+ configure_file("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Glib.resources.in"
+ "${GLIB_RESOURCE_MANIFEST}"
+ )
+
+ # Source Generation
+
+ foreach(FILE IN LISTS _CSS_FILES _XML_FILES)
+ list(APPEND _DEPS "${_WORKING_DIRECTORY}/${FILE}")
+ endforeach()
+
+
+ add_custom_command(OUTPUT "${GLIB_RESOURCE_C_FILE}"
+ WORKING_DIRECTORY "${_WORKING_DIRECTORY}"
+ COMMAND "${GLIB_COMPILE_RESOURCES}"
+ ARGS
+ "--target=${GLIB_RESOURCE_C_FILE}"
+ "--generate-source"
+ "--internal"
+ "${GLIB_RESOURCE_MANIFEST}"
+ VERBATIM
+ MAIN_DEPENDENCY "${GLIB_RESOURCE_MANIFEST}"
+ DEPENDS
+ ${_DEPS}
+ )
+
+ # Target Inclusion
+
+ target_sources("${TARGET}" PRIVATE
+ "${GLIB_RESOURCE_C_FILE}"
+ )
+endfunction()
+
+
+function(glib_add_schemas TARGET)
+ set(SINGLE_VALUE_ARGS "SCHEMA_DIR")
+ cmake_parse_arguments(
+ PARSE_ARGV 1
+ ""
+ "${OPTIONS}"
+ "${SINGLE_VALUE_ARGS}"
+ "${MULTI_VALUE_ARGS}"
+ )
+
+ if(NOT TARGET "${TARGET}")
+ message(FATAL_ERROR "Glib: Target '${TARGET}' does not exist")
+ endif()
+
+ if(NOT IS_ABSOLUTE "${_SCHEMA_DIR}")
+ get_filename_component(_SCHEMA_DIR "${_SCHEMA_DIR}" REALPATH)
+ endif()
+
+ if(NOT IS_DIRECTORY "${_SCHEMA_DIR}")
+ message(FATAL_ERROR "Glib: Directory '${_SCHEMA_DIR}' does not exists")
+ endif()
+
+ file(GLOB SCHAMA_FILES CONFIGURE_DEPENDS "${_SCHEMA_DIR}/*.gschema.xml")
+
+ add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/glib-2.0/schemas/gschemas.compiled"
+ WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
+ COMMAND "${GLIB_COMPILE_SCHEMAS_BIN}"
+ ARGS
+ "--targetdir=${CMAKE_CURRENT_BINARY_DIR}/glib-2.0/schemas"
+ "--strict"
+ "${_SCHEMA_DIR}"
+ VERBATIM
+ COMMENT "Compiling gsettings schemas"
+ DEPENDS
+ ${SCHEMA_FILES}
+ )
+
+ add_custom_target("${TARGET}_schemas" DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/glib-2.0/schemas/gschemas.compiled")
+
+ add_dependencies("${TARGET}" "${TARGET}_schemas")
+endfunction()
+
+
+function(glib_wrap_enums TARGET)
+ set(SINGLE_VALUE_ARGS
+ "HEADER_TEMPLATE"
+ "OUTPUT_NAME"
+ "SOURCE_TEMPLATE"
+ )
+ set(MULTI_VALUE_ARGS "HEADERS")
+ cmake_parse_arguments(
+ PARSE_ARGV 1
+ ""
+ "${OPTIONS}"
+ "${SINGLE_VALUE_ARGS}"
+ "${MULTI_VALUE_ARGS}"
+ )
+
+ if(NOT TARGET "${TARGET}")
+ message(FATAL_ERROR "Glib: Target '${TARGET}' does not exist")
+ endif()
+
+ if(NOT _HEADERS)
+ message(FATAL_ERROR "Glib: No headers to be parsed were specified")
+ endif()
+
+ if(NOT _HEADER_TEMPLATE)
+ message(STATUS "Glib: no header template was provided, skipping header generation")
+ set(_SKIP_HEADER YES)
+ endif()
+
+ if(NOT _SOURCE_TEMPLATE)
+ message(STATUS "Glib: no source template was provided, skipping header generation")
+ set(_SKIP_SOURCE YES)
+ endif()
+
+ if(NOT _OUTPUT_NAME)
+ message(FATAL_ERROR "Glib: No output name was specified")
+ endif()
+
+ if(_SKIP_HEADER AND _SKIP_SOURCE)
+ message(AUTHOR_WARNING "Glib: No templates were specified, skipping all generation")
+ return()
+ endif()
+
+ set(SOURCE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/src/${_OUTPUT_NAME}.c")
+ set(HEADER_FILE "${CMAKE_CURRENT_SOURCE_DIR}/src/${_OUTPUT_NAME}.h")
+
+ if(NOT _SKIP_HEADER)
+ add_custom_command(OUTPUT
+ ${HEADER_FILE}
+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ COMMAND "${GLIB_MKENUMS_BIN}"
+ ARGS
+ "--template=${_HEADER_TEMPLATE}"
+ "--output=${HEADER_FILE}"
+ ${_HEADERS}
+ VERBATIM
+ COMMENT "Generating enum interface header"
+ DEPENDS
+ ${_HEADERS}
+ ${_HEADER_TEMPLATE}
+ )
+ endif()
+
+ if(NOT _SKIP_SOURCE)
+ add_custom_command(OUTPUT
+ ${SOURCE_FILE}
+ WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+ COMMAND "${GLIB_MKENUMS_BIN}"
+ ARGS
+ "--template=${_SOURCE_TEMPLATE}"
+ "--output=${SOURCE_FILE}"
+ ${_HEADERS}
+ VERBATIM
+ COMMENT "Generating enum interface source"
+ DEPENDS
+ ${_HEADERS}
+ ${_SOURCE_TEMPLATE}
+ )
+ endif()
+
+ target_sources("${TARGET}" PRIVATE
+ "${SOURCE_FILE}"
+ )
+
+ if(NOT _SKIP_HEADER)
+ target_sources("${TARGET}" PUBLIC
+ FILE_SET HEADERS
+ FILES
+ "${HEADER_FILE}"
+ )
+ endif()
+
+endfunction()