diff options
Diffstat (limited to 'cmake/Modules/Glib.cmake')
| -rw-r--r-- | cmake/Modules/Glib.cmake | 315 |
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() |
