build: Add the CMake build option PNG_LIBCONF_HEADER

Running the pnglibconf scripts (script/*.awk) is not always possible.
An AWK interpreter is not always guaranteed to be available; and even
if it is, there are limitations when making cross-platform libpng
builds, especially when the differences between the host platform and
the target platform are significant. For example:
 * Building for the Windows (MinGW) target on a Unix development host;
 * Building for the iOS target on a macOS development host;
 * Building for the Android target on any development host.

In such scenarios, a preconfigured (i.e. prebuilt) pnglibconf.h file,
either taken from the libpng source tree or provided by the user who
wants to make a custom libpng build, becomes a necessity.

In this commit we introduce the build option `PNG_LIBCONF_HEADER` in
order to address this specific use case.

We also specify a version range (3.14...4.0) for the minimum required
CMake program, to future-proof the CMake build for just a little bit
longer.

Signed-off-by: Cosmin Truta <ctruta@gmail.com>
This commit is contained in:
Cosmin Truta 2025-04-28 20:44:53 +03:00
parent 69a3e5bfd1
commit 23bdc7a6c4
2 changed files with 106 additions and 17 deletions

View File

@ -14,7 +14,7 @@
# #
# SPDX-License-Identifier: libpng-2.0 # SPDX-License-Identifier: libpng-2.0
cmake_minimum_required(VERSION 3.14) cmake_minimum_required(VERSION 3.14...4.0)
set(PNGLIB_MAJOR 1) set(PNGLIB_MAJOR 1)
set(PNGLIB_MINOR 6) set(PNGLIB_MINOR 6)
@ -45,14 +45,35 @@ set(PNG_DEBUG_POSTFIX "d"
CACHE STRING "Postfix to append to library file names under the Debug configuration") CACHE STRING "Postfix to append to library file names under the Debug configuration")
# Allow the users to import their own extra configuration settings. # Allow the users to import their own extra configuration settings.
# Those settings can be either passed via DFA_XTRA if they are in DFA form
# (such as "pngusr.dfa"), or via PNG_LIBCONF_HEADER if they are in prebuilt
# header file form (such as "scripts/pnglibconf.h.prebuilt"), but not both.
# For platforms such as Android or iOS, or in certain cross-platform build
# scenarios, having a valid PNG_LIBCONF_HEADER is mandatory.
set(DFA_XTRA "" set(DFA_XTRA ""
CACHE FILEPATH "File containing extra configuration settings") CACHE FILEPATH "DFA file containing customized build configuration settings for libpng")
set(PNG_LIBCONF_HEADER ""
CACHE FILEPATH "C header file containing customized build configuration settings for libpng")
set(PNG_LIBCONF_HEADER_PREBUILT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/pnglibconf.h.prebuilt")
if(ANDROID OR IOS)
set(PNG_LIBCONF_HEADER "${PNG_LIBCONF_HEADER_PREBUILT}")
endif()
if((NOT DFA_XTRA STREQUAL "") AND (NOT PNG_LIBCONF_HEADER STREQUAL ""))
message(SEND_ERROR
"The options DFA_XTRA=\"${DFA_XTRA}\" and PNG_LIBCONF_HEADER=\"${PNG_LIBCONF_HEADER}\" "
"are mutually exclusive")
endif()
# Allow the users to switch on/off various library build types. # Allow the users to switch on/off various library build types.
option(PNG_SHARED "Build libpng as a shared library" ON) option(PNG_SHARED "Build libpng as a shared library" ON)
option(PNG_STATIC "Build libpng as a static library" ON) option(PNG_STATIC "Build libpng as a static library" ON)
if(APPLE) if(APPLE)
option(PNG_FRAMEWORK "Build libpng as a framework bundle" ON) option(PNG_FRAMEWORK "Build libpng as a framework bundle" ON)
else()
option(PNG_FRAMEWORK "Build libpng as a framework bundle (not available on this platform)" OFF)
endif()
if(NOT APPLE AND PNG_FRAMEWORK)
message(SEND_ERROR "The option PNG_FRAMEWORK should not be set on this platform")
endif() endif()
# Allow the users to switch on/off the auxiliary build and test artifacts. # Allow the users to switch on/off the auxiliary build and test artifacts.
@ -114,6 +135,7 @@ if(PNG_BUILD_ZLIB)
endif() endif()
endif() endif()
# Find the prerequisite libraries.
find_package(ZLIB REQUIRED) find_package(ZLIB REQUIRED)
if(UNIX if(UNIX
@ -348,26 +370,48 @@ int main(void) { return 0; }
file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/conftest.map") file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/conftest.map")
endif() endif()
# Find an AWK language processor. if(PNG_LIBCONF_HEADER STREQUAL "")
# Start with specific AWK implementations like gawk and nawk, which are # No custom configuration header file has been specified, so we build it
# known to work with our scripts, then fall back to the system awk. # from our DFA files and (optionally) out of the user-supplied DFA file.
find_program(AWK NAMES gawk nawk awk) # Find an AWK language processor.
if(AWK) # Start with specific AWK implementations like gawk and nawk, which are
# known to work with our scripts, then fall back to the system awk.
find_program(AWK NAMES gawk nawk awk)
if(AWK)
message(STATUS "Found AWK program: ${AWK}") message(STATUS "Found AWK program: ${AWK}")
else() else()
message(STATUS "Could not find an AWK-compatible program") message(STATUS "Could not find an AWK-compatible program")
endif()
endif() endif()
if(NOT AWK OR (ANDROID OR IOS)) # Include the internal module PNGCheckLibconf.cmake
# No awk available to generate sources; use pre-built pnglibconf.h include(${CMAKE_CURRENT_SOURCE_DIR}/scripts/cmake/PNGCheckLibconf.cmake)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/pnglibconf.h.prebuilt
${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.h) if(NOT PNG_LIBCONF_HEADER STREQUAL "")
# Configure libpng with the user-defined pnglibconf.h file.
png_check_libconf(HEADER "${PNG_LIBCONF_HEADER}")
configure_file("${PNG_LIBCONF_HEADER}"
${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.h
@ONLY)
add_custom_target(png_genfiles)
elseif(NOT AWK)
# No AWK program available to generate pnglibconf.h.
# Configure libpng with pnglibconf.h.prebuilt.
png_check_libconf(HEADER "${PNG_LIBCONF_HEADER_PREBUILT}")
configure_file("${PNG_LIBCONF_HEADER_PREBUILT}"
${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.h
@ONLY)
add_custom_target(png_genfiles) add_custom_target(png_genfiles)
else() else()
png_check_libconf(DFA_XTRA "${DFA_XTRA}")
# Include the internal module PNGGenConfig.cmake # Include the internal module PNGGenConfig.cmake
include(${CMAKE_CURRENT_SOURCE_DIR}/scripts/cmake/PNGGenConfig.cmake) include(${CMAKE_CURRENT_SOURCE_DIR}/scripts/cmake/PNGGenConfig.cmake)
# Copy the awk scripts, converting their line endings to Unix (LF) # Work around a limitation of various Windows AWK programs that are
# unable to process CRLF-terminated AWK scripts.
# Copy these AWK scripts to a temporary location, converting their
# line endings from Windows (CRLF) to Unix (LF) at the destination.
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/checksym.awk configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/checksym.awk
${CMAKE_CURRENT_BINARY_DIR}/scripts/checksym.awk ${CMAKE_CURRENT_BINARY_DIR}/scripts/checksym.awk
@ONLY @ONLY
@ -502,7 +546,7 @@ else()
"${CMAKE_CURRENT_BINARY_DIR}/scripts/symbols.chk" png_scripts_symbols_chk "${CMAKE_CURRENT_BINARY_DIR}/scripts/symbols.chk" png_scripts_symbols_chk
"${CMAKE_CURRENT_BINARY_DIR}/scripts/symbols.out" png_scripts_symbols_out "${CMAKE_CURRENT_BINARY_DIR}/scripts/symbols.out" png_scripts_symbols_out
"${CMAKE_CURRENT_BINARY_DIR}/scripts/vers.out" png_scripts_vers_out) "${CMAKE_CURRENT_BINARY_DIR}/scripts/vers.out" png_scripts_vers_out)
endif(NOT AWK OR (ANDROID OR IOS)) endif()
# List the source code files. # List the source code files.
set(libpng_public_hdrs set(libpng_public_hdrs
@ -516,7 +560,7 @@ set(libpng_private_hdrs
pnginfo.h pnginfo.h
pngstruct.h pngstruct.h
) )
if(AWK AND NOT (ANDROID OR IOS)) if(AWK)
list(APPEND libpng_private_hdrs "${CMAKE_CURRENT_BINARY_DIR}/pngprefix.h") list(APPEND libpng_private_hdrs "${CMAKE_CURRENT_BINARY_DIR}/pngprefix.h")
endif() endif()
set(libpng_sources set(libpng_sources

View File

@ -0,0 +1,45 @@
# PNGConfig.cmake
# Utility functions for configuring and building libpng
# Copyright (c) 2025 Cosmin Truta
#
# Use, modification and distribution are subject to
# the same licensing terms and conditions as libpng.
# Please see the copyright notice in png.h or visit
# http://libpng.org/pub/png/src/libpng-LICENSE.txt
#
# SPDX-License-Identifier: libpng-2.0
# Check libconf file (pnglibconf.h.* or *.dfa):
# png_check_libconf([HEADER <file>] [DFA_XTRA <file>])
function(png_check_libconf)
set(options)
set(oneValueArgs HEADER DFA_XTRA)
set(multiValueArgs)
cmake_parse_arguments(_CHK "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(_CHK_HEADER AND _CHK_DFA_XTRA)
message(FATAL_ERROR "png_check_libconf: Mutually-exclusive arguments: HEADER and DFA_XTRA")
endif()
if(_CHK_HEADER)
if(EXISTS "${_CHK_HEADER}")
if("x${_CHK_HEADER}" STREQUAL "x${PNG_LIBCONF_HEADER_PREBUILT}")
message(STATUS "Using standard libconf header: ${_CHK_HEADER}")
else()
message(STATUS "Using custom libconf header: ${_CHK_HEADER}")
endif()
else()
message(SEND_ERROR "Could not find libconf header: ${_CHK_HEADER}")
endif()
else()
if("x${_CHK_DFA_XTRA}" STREQUAL "x")
message(STATUS "Creating standard configuration")
elseif(EXISTS "${_CHK_DFA_XTRA}")
message(STATUS "Creating custom configuration with DFA_XTRA file: ${_CHK_DFA_XTRA}")
else()
message(SEND_ERROR "Could not find DFA_XTRA file: ${_CHK_DFA_XTRA}")
endif()
endif()
endfunction()