# SPDX-FileCopyrightText: 2025 Felix Morgner # 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}/$/${_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=$" "--library-path=$" "$,PREPEND,-I>" "$,PREPEND,--pkg=>" "$" "--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 " ${XML_FILE}\n") endforeach() foreach(CSS_FILE IN LISTS _CSS_FILES) string(APPEND GLIB_RESOURCE_FILES " ${CSS_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()