• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#                          __  __            _
2#                       ___\ \/ /_ __   __ _| |_
3#                      / _ \\  /| '_ \ / _` | __|
4#                     |  __//  \| |_) | (_| | |_
5#                      \___/_/\_\ .__/ \__,_|\__|
6#                               |_| XML parser
7#
8# Copyright (c) 2010      Patrick Spendrin <ps_ml@gmx.de>
9# Copyright (c) 2012      Karl Waclawek <karl@waclawek.net>
10# Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org>
11# Copyright (c) 2016      Sergei Nikulov <sergey.nikulov@gmail.com>
12# Copyright (c) 2016      Björn Lindahl <bjorn.lindahl@foi.se>
13# Copyright (c) 2016      Tobias Taschner <github@tc84.de>
14# Copyright (c) 2016      Ben Boeckel <ben.boeckel@kitware.com>
15# Copyright (c) 2017      Rhodri James <rhodri@wildebeest.org.uk>
16# Copyright (c) 2017      Rolf Eike Beer <eike@sf-mail.de>
17# Copyright (c) 2017      Stephen Groat <stephen@groat.us>
18# Copyright (c) 2017      Franek Korta <fkorta@gmail.com>
19# Copyright (c) 2018      pedro-vicente <pedro.vicente@space-research.org>
20# Copyright (c) 2018      Frank Rast <frank.rast@gefeg.com>
21# Copyright (c) 2018      userwithuid <userwithuid@gmail.com>
22# Copyright (c) 2018      Yury Gribov <tetra2005@gmail.com>
23# Copyright (c) 2019      Kishore Kunche <kishore.kunche@intel.com>
24# Copyright (c) 2019      xantares <xantares09@hotmail.com>
25# Copyright (c) 2019      Mohammed Khajapasha <mohammed.khajapasha@intel.com>
26# Copyright (c) 2019      David Loffredo <loffredo@steptools.com>
27# Copyright (c) 2019      Bhargava Shastry <bhargava.shastry@ethereum.org>
28# Copyright (c) 2020      Maciej Sroczyński <macieksroczynski@poczta.fm>
29# Copyright (c) 2020      Gulliver <gulliver@traumkristalle.net>
30# Copyright (c) 2020      Thomas Beutlich <tc@tbeu.de>
31# Copyright (c) 2021      Alex Richardson <Alexander.Richardson@cl.cam.ac.uk>
32# Copyright (c) 2022      Johnny Jazeix <jazeix@gmail.com>
33# Copyright (c) 2022      David Faure <david.faure@kdab.com>
34# Unlike most of Expat,
35# this file is copyrighted under the BSD-license for buildsystem files of KDE.
36
37cmake_minimum_required(VERSION 3.1.3)
38
39project(expat
40    VERSION
41        2.5.0
42    LANGUAGES
43        C
44)
45
46set(PACKAGE_BUGREPORT "expat-bugs@libexpat.org")
47set(PACKAGE_NAME "expat")
48set(PACKAGE_VERSION "${PROJECT_VERSION}")
49set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
50set(PACKAGE_TARNAME "${PACKAGE_NAME}")
51
52include(CMakePackageConfigHelpers)
53include(GNUInstallDirs)
54
55#
56# Configuration defaults
57#
58if(WINCE)
59    set(_EXPAT_BUILD_TOOLS_DEFAULT OFF)
60else()
61    set(_EXPAT_BUILD_TOOLS_DEFAULT ON)
62endif()
63if(MSVC OR NOT _EXPAT_BUILD_TOOLS_DEFAULT)
64    set(_EXPAT_BUILD_DOCS_DEFAULT OFF)
65else()
66    find_program(DOCBOOK_TO_MAN NAMES docbook2x-man db2x_docbook2man docbook2man docbook-to-man)
67    if(DOCBOOK_TO_MAN)
68        set(_EXPAT_BUILD_DOCS_DEFAULT ON)
69    else()
70        set(_EXPAT_BUILD_DOCS_DEFAULT OFF)
71    endif()
72endif()
73if(MSVC)
74    set(_EXPAT_BUILD_PKGCONFIG_DEFAULT OFF)
75else()
76    set(_EXPAT_BUILD_PKGCONFIG_DEFAULT ON)
77endif()
78if(DEFINED BUILD_SHARED_LIBS)
79    set(_EXPAT_SHARED_LIBS_DEFAULT ${BUILD_SHARED_LIBS})
80else()
81    set(_EXPAT_SHARED_LIBS_DEFAULT ON)
82endif()
83if(NOT CMAKE_BUILD_TYPE)
84    set(CMAKE_BUILD_TYPE NoConfig)  # so that accessing EXPAT_*_POSTFIX will be waterproof
85endif()
86string(TOUPPER "${CMAKE_BUILD_TYPE}" _EXPAT_BUILD_TYPE_UPPER)
87
88#
89# Configuration
90#
91
92macro(expat_shy_set var default cache type desc)
93    # Macro expat_shy_set came into life because:
94    # - Expat was previously using an inconsistent mix of CMake's native set()
95    #   and option() to define public build time options.
96    # - option() is more friendly than set() with regard to configuring an
97    #   external project that is pulled in by means of add_subdirectory() --
98    #   see comments in issue #597 -- so we wanted to get away from set().
99    # - option() auto-converts non-bool values to bool when writing to the CMake
100    #   cache, so we needed something that supports non-bool better and hence
101    #   wanted to get away from plain option(), too.
102    #
103    # As a result, this function serves as a hybrid between CMake's regular set()
104    # and option(): from set() it takes support for non-bool types and the function
105    # name and signature whereas from option() (with policy CMP0077 mode NEW) it
106    # takes being shy when a value has previously been defined for that variable.
107    #
108    # So that resolves all need for set(.. FORCE) when pulling in Expat by means of
109    # add_subdirectory().
110    #
111    if(NOT ${cache} STREQUAL "CACHE")
112        message(SEND_ERROR "Macro usage is: expat_shy_set(var default CACHE type desc)")
113    endif()
114
115    if(DEFINED ${var})
116        # NOTE: The idea is to (ideally) only add to the cache if
117        #       there is no cache entry, yet.  "if(DEFINED CACHE{var})"
118        #       requires CMake >=3.14.
119        if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.14" AND NOT DEFINED "CACHE{${var}}")
120            set("${var}" "${${var}}" CACHE "${type}" "${desc}")
121        endif()
122    else()
123        set("${var}" "${default}" CACHE "${type}" "${desc}")
124    endif()
125endmacro()
126
127expat_shy_set(EXPAT_BUILD_TOOLS ${_EXPAT_BUILD_TOOLS_DEFAULT} CACHE BOOL "Build the xmlwf tool for expat library")
128expat_shy_set(EXPAT_BUILD_EXAMPLES ON CACHE BOOL "Build the examples for expat library")
129expat_shy_set(EXPAT_BUILD_TESTS ON CACHE BOOL "Build the tests for expat library")
130expat_shy_set(EXPAT_SHARED_LIBS ${_EXPAT_SHARED_LIBS_DEFAULT} CACHE BOOL "Build a shared expat library")
131expat_shy_set(EXPAT_BUILD_DOCS ${_EXPAT_BUILD_DOCS_DEFAULT} CACHE BOOL "Build man page for xmlwf")
132expat_shy_set(EXPAT_BUILD_FUZZERS OFF CACHE BOOL "Build fuzzers for the expat library")
133expat_shy_set(EXPAT_BUILD_PKGCONFIG ${_EXPAT_BUILD_PKGCONFIG_DEFAULT} CACHE BOOL "Build pkg-config file")
134expat_shy_set(EXPAT_OSSFUZZ_BUILD OFF CACHE BOOL "Build fuzzers via ossfuzz for the expat library")
135if(UNIX OR _EXPAT_HELP)
136    expat_shy_set(EXPAT_WITH_LIBBSD OFF CACHE BOOL "Utilize libbsd (for arc4random_buf)")
137endif()
138expat_shy_set(EXPAT_ENABLE_INSTALL ON CACHE BOOL "Install expat files in cmake install target")
139expat_shy_set(EXPAT_CONTEXT_BYTES 1024 CACHE STRING "Define to specify how much context to retain around the current parse point")
140mark_as_advanced(EXPAT_CONTEXT_BYTES)
141expat_shy_set(EXPAT_DTD ON CACHE BOOL "Define to make parameter entity parsing functionality available")
142mark_as_advanced(EXPAT_DTD)
143expat_shy_set(EXPAT_NS ON CACHE BOOL "Define to make XML Namespaces functionality available")
144mark_as_advanced(EXPAT_NS)
145expat_shy_set(EXPAT_WARNINGS_AS_ERRORS OFF CACHE BOOL "Treat all compiler warnings as errors")
146if(UNIX OR _EXPAT_HELP)
147    expat_shy_set(EXPAT_DEV_URANDOM ON CACHE BOOL "Define to include code reading entropy from `/dev/urandom'.")
148    expat_shy_set(EXPAT_WITH_GETRANDOM "AUTO" CACHE STRING "Make use of getrandom function (ON|OFF|AUTO) [default=AUTO]")
149    expat_shy_set(EXPAT_WITH_SYS_GETRANDOM "AUTO" CACHE STRING "Make use of syscall SYS_getrandom (ON|OFF|AUTO) [default=AUTO]")
150    mark_as_advanced(EXPAT_DEV_URANDOM)
151endif()
152expat_shy_set(EXPAT_CHAR_TYPE "char" CACHE STRING "Character type to use (char|ushort|wchar_t) [default=char]")
153expat_shy_set(EXPAT_ATTR_INFO OFF CACHE BOOL "Define to allow retrieving the byte offsets for attribute names and values")
154mark_as_advanced(EXPAT_ATTR_INFO)
155expat_shy_set(EXPAT_LARGE_SIZE OFF CACHE BOOL "Make XML_GetCurrent* functions return <(unsigned) long long> rather than <(unsigned) long>")
156mark_as_advanced(EXPAT_LARGE_SIZE)
157expat_shy_set(EXPAT_MIN_SIZE OFF CACHE BOOL "Get a smaller (but slower) parser (in particular avoid multiple copies of the tokenizer)")
158mark_as_advanced(EXPAT_MIN_SIZE)
159if(MSVC OR _EXPAT_HELP)
160    expat_shy_set(EXPAT_MSVC_STATIC_CRT OFF CACHE BOOL "Use /MT flag (static CRT) when compiling in MSVC")
161endif()
162if(NOT _EXPAT_HELP)
163    expat_shy_set(_EXPAT_M32 OFF CACHE BOOL "(Unofficial!) Produce 32bit code with -m32")
164    mark_as_advanced(_EXPAT_M32)
165endif()
166
167if(EXPAT_BUILD_TESTS)
168    # We have to call enable_language() before modifying any CMAKE_CXX_* variables
169    enable_language(CXX)
170endif()
171
172#
173# Environment checks
174#
175if(EXPAT_WITH_LIBBSD)
176    find_library(LIB_BSD NAMES bsd)
177    if(NOT LIB_BSD)
178        message(SEND_ERROR "EXPAT_WITH_LIBBSD option is enabled, but libbsd was not found")
179    else()
180        set(HAVE_LIBBSD TRUE)
181    endif()
182endif()
183
184if(MSVC)
185    # For the three types of MSVC version values, please see:
186    # - https://cmake.org/cmake/help/latest/variable/MSVC_VERSION.html
187    # - https://sourceforge.net/p/predef/wiki/Compilers/
188    # - https://en.wikipedia.org/wiki/Microsoft_Visual_Studio#History
189    set(_EXPAT_MSVC_REQUIRED_INT 1800)  # i.e. 12.0/2013/1800; see PR #426
190    set(_EXPAT_MSVC_SUPPORTED_INT 1910)
191    set(_EXPAT_MSVC_SUPPORTED_DISPLAY "Visual Studio 15.0/2017/${_EXPAT_MSVC_SUPPORTED_INT}")
192
193    if(MSVC_VERSION VERSION_LESS ${_EXPAT_MSVC_SUPPORTED_INT})
194        if(MSVC_VERSION VERSION_LESS ${_EXPAT_MSVC_REQUIRED_INT})
195            message(SEND_ERROR "MSVC_VERSION ${MSVC_VERSION} is TOO OLD to compile Expat without errors.")
196            message(SEND_ERROR "Please use officially supported ${_EXPAT_MSVC_SUPPORTED_DISPLAY} or later.  Thank you!")
197        else()
198            message(WARNING "MSVC_VERSION ${MSVC_VERSION} is NOT OFFICIALLY SUPPORTED by Expat.")
199            message(WARNING "Please use ${_EXPAT_MSVC_SUPPORTED_DISPLAY} or later.  Thank you!")
200        endif()
201    endif()
202endif()
203
204macro(_expat_copy_bool_int source_ref dest_ref)
205    if(${source_ref})
206        set(${dest_ref} 1)
207    else()
208        set(${dest_ref} 0)
209    endif()
210endmacro()
211
212if(EXPAT_LARGE_SIZE)
213    add_definitions(-DXML_LARGE_SIZE)
214endif()
215
216if(EXPAT_MIN_SIZE)
217    add_definitions(-DXML_MIN_SIZE)
218endif()
219
220if(EXPAT_CHAR_TYPE STREQUAL "char")
221    set(_EXPAT_UNICODE OFF)
222    set(_EXPAT_UNICODE_WCHAR_T OFF)
223elseif(EXPAT_CHAR_TYPE STREQUAL "ushort")
224    set(_EXPAT_UNICODE ON)
225    set(_EXPAT_UNICODE_WCHAR_T OFF)
226    if(EXPAT_BUILD_EXAMPLES)
227        message(SEND_ERROR "Examples can not be built with option -DEXPAT_CHAR_TYPE=ushort. Please pass -DEXPAT_CHAR_TYPE=(char|wchar_t) or -DEXPAT_BUILD_EXAMPLES=OFF.")
228    endif()
229    if(EXPAT_BUILD_TESTS)
230        message(SEND_ERROR "The testsuite can not be built with option -DEXPAT_CHAR_TYPE=ushort. Please pass -DEXPAT_CHAR_TYPE=(char|wchar_t) or -DEXPAT_BUILD_TESTS=OFF.")
231    endif()
232    if(EXPAT_BUILD_TOOLS)
233        message(SEND_ERROR "The xmlwf tool can not be built with option -DEXPAT_CHAR_TYPE=ushort. Please pass -DEXPAT_CHAR_TYPE=(char|wchar_t) or -DEXPAT_BUILD_TOOLS=OFF.")
234    endif()
235elseif(EXPAT_CHAR_TYPE STREQUAL "wchar_t")
236    set(_EXPAT_UNICODE ON)
237    set(_EXPAT_UNICODE_WCHAR_T ON)
238    if(NOT WIN32)
239        string(FIND "${CMAKE_C_FLAGS}" "-fshort-wchar" _expat_short_wchar_found)
240        if(${_expat_short_wchar_found} EQUAL "-1")
241            message(SEND_ERROR "Configuration -DEXPAT_CHAR_TYPE=wchar_t requires -DCMAKE_{C,CXX}_FLAGS=-fshort-wchar (which was not found) and libc compiled with -fshort-wchar, too.")
242        endif()
243        if (EXPAT_BUILD_TOOLS)
244            message(SEND_ERROR "The xmlwf tool can not be built with option -DEXPAT_CHAR_TYPE=wchar_t outside of Windows. Please pass -DEXPAT_CHAR_TYPE=char or -DEXPAT_BUILD_TOOLS=OFF.")
245        endif()
246    endif()
247else()
248    message(SEND_ERROR "Option -DEXPAT_CHAR_TYPE=(char|ushort|wchar_t) cannot be \"${EXPAT_CHAR_TYPE}\".")
249endif()
250
251if(_EXPAT_UNICODE)
252    add_definitions(-DXML_UNICODE)              # for unsigned short
253    if(_EXPAT_UNICODE_WCHAR_T)
254        add_definitions(-DXML_UNICODE_WCHAR_T)  # for wchar_t
255    endif()
256endif()
257
258include(${CMAKE_CURRENT_LIST_DIR}/ConfigureChecks.cmake)
259
260macro(evaluate_detection_results use_ref have_ref thing_lower thing_title)
261    if(${use_ref} AND NOT (${use_ref} STREQUAL "AUTO") AND NOT ${have_ref})
262        message(SEND_ERROR
263                "Use of ${thing_lower} was enforced by ${use_ref}=ON but it could not be found.")
264    elseif(NOT ${use_ref} AND ${have_ref})
265        message("${thing_title} was found but it will not be used due to ${use_ref}=OFF.")
266        set(${have_ref} 0)
267    endif()
268endmacro()
269
270if(NOT WIN32)
271    evaluate_detection_results(EXPAT_WITH_GETRANDOM HAVE_GETRANDOM "function getrandom" "Function getrandom")
272    evaluate_detection_results(EXPAT_WITH_SYS_GETRANDOM HAVE_SYSCALL_GETRANDOM "syscall SYS_getrandom" "Syscall SYS_getrandom")
273endif()
274
275_expat_copy_bool_int(EXPAT_ATTR_INFO        XML_ATTR_INFO)
276_expat_copy_bool_int(EXPAT_DTD              XML_DTD)
277_expat_copy_bool_int(EXPAT_LARGE_SIZE       XML_LARGE_SIZE)
278_expat_copy_bool_int(EXPAT_MIN_SIZE         XML_MIN_SIZE)
279_expat_copy_bool_int(EXPAT_NS               XML_NS)
280if(NOT WIN32)
281    _expat_copy_bool_int(EXPAT_DEV_URANDOM  XML_DEV_URANDOM)
282endif()
283set(XML_CONTEXT_BYTES ${EXPAT_CONTEXT_BYTES})
284
285macro(expat_install)
286    if(EXPAT_ENABLE_INSTALL)
287        install(${ARGN})
288    endif()
289endmacro()
290
291configure_file(expat_config.h.cmake "${CMAKE_CURRENT_BINARY_DIR}/expat_config.h")
292expat_install(FILES "${CMAKE_CURRENT_BINARY_DIR}/expat_config.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
293
294
295set(EXTRA_COMPILE_FLAGS)
296if(FLAG_NO_STRICT_ALIASING)
297    set(EXTRA_COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -fno-strict-aliasing")
298endif()
299if(FLAG_VISIBILITY)
300  if(EXPAT_SHARED_LIBS)
301     add_definitions(-DXML_ENABLE_VISIBILITY=1)
302  endif()
303  set(EXTRA_COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -fvisibility=hidden")
304endif()
305if(MINGW)
306    # Without __USE_MINGW_ANSI_STDIO the compiler produces a false positive
307    set(EXTRA_COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -Wno-pedantic-ms-format")
308endif()
309if (EXPAT_WARNINGS_AS_ERRORS)
310    if(MSVC)
311        add_definitions(/WX)
312    else()
313        set(EXTRA_COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -Werror")
314    endif()
315endif()
316set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_COMPILE_FLAGS}")
317set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_COMPILE_FLAGS}")
318
319if (MSVC)
320    if (EXPAT_MSVC_STATIC_CRT)
321        message("-- Using static CRT ${EXPAT_MSVC_STATIC_CRT}")
322        foreach(flag_var
323                CMAKE_CXX_FLAGS_${_EXPAT_BUILD_TYPE_UPPER}
324                CMAKE_CXX_FLAGS_DEBUG
325                CMAKE_CXX_FLAGS_RELEASE
326                CMAKE_CXX_FLAGS_MINSIZEREL
327                CMAKE_CXX_FLAGS_RELWITHDEBINFO
328                CMAKE_C_FLAGS_${_EXPAT_BUILD_TYPE_UPPER}
329                CMAKE_C_FLAGS_DEBUG
330                CMAKE_C_FLAGS_RELEASE
331                CMAKE_C_FLAGS_MINSIZEREL
332                CMAKE_C_FLAGS_RELWITHDEBINFO
333                )
334            string(REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
335        endforeach()
336    endif()
337endif()
338
339if(_EXPAT_M32 AND NOT MSVC)
340    foreach(flag_var
341            CMAKE_CXX_FLAGS_${_EXPAT_BUILD_TYPE_UPPER}
342            CMAKE_CXX_FLAGS_DEBUG
343            CMAKE_CXX_FLAGS_RELEASE
344            CMAKE_CXX_FLAGS_MINSIZEREL
345            CMAKE_CXX_FLAGS_RELWITHDEBINFO
346            CMAKE_C_FLAGS_${_EXPAT_BUILD_TYPE_UPPER}
347            CMAKE_C_FLAGS_DEBUG
348            CMAKE_C_FLAGS_RELEASE
349            CMAKE_C_FLAGS_MINSIZEREL
350            CMAKE_C_FLAGS_RELWITHDEBINFO
351            )
352        set(${flag_var} "${${flag_var}} -m32")
353    endforeach()
354endif()
355
356include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/lib)
357if(MSVC)
358    add_definitions(-D_CRT_SECURE_NO_WARNINGS -wd4996)
359endif()
360
361#
362# C library
363#
364set(_EXPAT_C_SOURCES
365    lib/xmlparse.c
366    lib/xmlrole.c
367    lib/xmltok.c
368# NOTE: ISO C forbids an empty translation unit
369#   lib/xmltok_impl.c
370#   lib/xmltok_ns.c
371)
372
373if(EXPAT_SHARED_LIBS)
374    set(_SHARED SHARED)
375    if(WIN32)
376        macro(_expat_def_file_toggle source_var target_var)
377            if(${source_var})
378                set(${target_var} " ")  # i.e. not commented out, a single space
379            else()
380                set(${target_var} ";")  # i.e. commented out
381            endif()
382        endmacro()
383
384        _expat_def_file_toggle(EXPAT_DTD _EXPAT_COMMENT_DTD)
385        _expat_def_file_toggle(EXPAT_ATTR_INFO _EXPAT_COMMENT_ATTR_INFO)
386
387        configure_file("${CMAKE_CURRENT_SOURCE_DIR}/lib/libexpat.def.cmake" "${CMAKE_CURRENT_BINARY_DIR}/lib/libexpat.def")
388        set(_EXPAT_EXTRA_SOURCES ${_EXPAT_EXTRA_SOURCES} "${CMAKE_CURRENT_BINARY_DIR}/lib/libexpat.def")
389
390        # Add DLL version
391        string(REPLACE "." "," _EXPAT_DLL_VERSION ${PROJECT_VERSION}.0)
392        set(_EXPAT_EXTRA_SOURCES ${_EXPAT_EXTRA_SOURCES} win32/version.rc)
393    endif()
394else()
395    set(_SHARED STATIC)
396endif()
397
398add_library(expat ${_SHARED} ${_EXPAT_C_SOURCES} ${_EXPAT_EXTRA_SOURCES})
399if(_EXPAT_LIBM_FOUND)
400    target_link_libraries(expat m)
401endif()
402if(EXPAT_WITH_LIBBSD)
403    target_link_libraries(expat ${LIB_BSD})
404endif()
405
406#
407# Library filename postfix
408#
409if(_EXPAT_UNICODE)
410    set(_POSTFIX_WIDE "w")
411endif()
412
413if(MSVC AND NOT EXPAT_SHARED_LIBS)
414    if(EXPAT_MSVC_STATIC_CRT)
415        set(_POSTFIX_CRT "MT")
416    else()
417        set(_POSTFIX_CRT "MD")
418    endif()
419endif()
420
421foreach(build_type_upper
422        ${_EXPAT_BUILD_TYPE_UPPER}
423        DEBUG
424        RELEASE
425        MINSIZEREL
426        RELWITHDEBINFO
427        )
428    if(WIN32 AND build_type_upper STREQUAL "DEBUG")
429        set(_POSTFIX_DEBUG "d")
430    else()
431        set(_POSTFIX_DEBUG "")  # needs a reset because of being looped
432    endif()
433
434    expat_shy_set(EXPAT_${build_type_upper}_POSTFIX "${_POSTFIX_WIDE}${_POSTFIX_DEBUG}${_POSTFIX_CRT}" CACHE STRING "Library filename postfix for build type ${build_type_upper}; yields filenames libexpat<postfix=[w][d][MD|MT]>.(dll|dylib|lib|so)")
435    mark_as_advanced(EXPAT_${build_type_upper}_POSTFIX)
436    set_property(TARGET expat PROPERTY ${build_type_upper}_POSTFIX ${EXPAT_${build_type_upper}_POSTFIX})
437endforeach()
438
439set(LIBCURRENT 9)    # sync
440set(LIBREVISION 10)  # with
441set(LIBAGE 8)        # configure.ac!
442math(EXPR LIBCURRENT_MINUS_AGE "${LIBCURRENT} - ${LIBAGE}")
443
444if(NOT WIN32)
445    set_property(TARGET expat PROPERTY VERSION ${LIBCURRENT_MINUS_AGE}.${LIBAGE}.${LIBREVISION})
446    set_property(TARGET expat PROPERTY SOVERSION ${LIBCURRENT_MINUS_AGE})
447    set_property(TARGET expat PROPERTY NO_SONAME ${NO_SONAME})
448
449    if(APPLE)
450        if(NOT CMAKE_VERSION VERSION_GREATER_EQUAL 3.17)
451            message(FATAL_ERROR "Expat requires CMake >=3.17 on platform \"APPLE\".")
452        endif()
453
454        # NOTE: This intends to talk CMake into compatiblity with GNU Libtool
455        math(EXPR _EXPAT_MACHO_COMPATIBILITY_VERSION "${LIBCURRENT} + 1")
456        set(_EXPAT_MACHO_CURRENT_VERSION "${_EXPAT_MACHO_COMPATIBILITY_VERSION}.${LIBREVISION}")
457        set_property(TARGET expat PROPERTY MACHO_COMPATIBILITY_VERSION ${_EXPAT_MACHO_COMPATIBILITY_VERSION})
458        set_property(TARGET expat PROPERTY MACHO_CURRENT_VERSION ${_EXPAT_MACHO_CURRENT_VERSION})
459    endif()
460endif()
461
462if(MINGW AND EXPAT_SHARED_LIBS)
463    set_target_properties(expat PROPERTIES SUFFIX "-${LIBCURRENT_MINUS_AGE}.dll")
464endif()
465
466if(WIN32 AND NOT MINGW)
467    # NOTE: This avoids a name collision with Expat.dll of Perl's XML::Parser::Expat
468    #       on Windows by resorting to filename libexpat.dll since Expat 1.95.3.
469    #       Everything but MSVC is already adding prefix "lib", automatically.
470    # NOTE: "set_property(TARGET expat PROPERTY PREFIX lib)" would only affect *.dll
471    #       files but not *.lib files, so we have to rely on property OUTPUT_NAME, instead.
472    #       Target property <CONFIG>_POSTFIX still applies.
473    set(_EXPAT_OUTPUT_NAME libexpat)
474    set_property(TARGET expat PROPERTY OUTPUT_NAME ${_EXPAT_OUTPUT_NAME})
475else()
476    set(_EXPAT_OUTPUT_NAME expat)
477endif()
478
479target_include_directories(expat
480    INTERFACE
481        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/lib>
482        $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
483        $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
484)
485
486if(WIN32 AND EXPAT_SHARED_LIBS)
487    target_compile_definitions(expat PRIVATE VER_FILEVERSION=${_EXPAT_DLL_VERSION})
488endif()
489
490expat_install(TARGETS expat EXPORT expat
491                      RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
492                      LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
493                      ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
494
495expat_install(FILES lib/expat.h lib/expat_external.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
496
497#
498# pkg-config file
499#
500if(EXPAT_BUILD_PKGCONFIG)
501    if(CMAKE_INSTALL_LIBDIR MATCHES "^/")
502        set(_expat_pkgconfig_libdir "${CMAKE_INSTALL_LIBDIR}")
503    else()
504        set(_expat_pkgconfig_libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
505    endif()
506
507    if(CMAKE_INSTALL_INCLUDEDIR MATCHES "^/")
508        set(_expat_pkgconfig_includedir "${CMAKE_INSTALL_INCLUDEDIR}")
509    else()
510        set(_expat_pkgconfig_includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
511    endif()
512
513    set_target_properties(expat PROPERTIES
514        pkgconfig_prefix "${CMAKE_INSTALL_PREFIX}"
515        pkgconfig_exec_prefix "\${prefix}"
516        pkgconfig_libdir "${_expat_pkgconfig_libdir}"
517        pkgconfig_includedir "${_expat_pkgconfig_includedir}"
518        pkgconfig_version "${PACKAGE_VERSION}")
519
520    foreach(_build_type ${CMAKE_BUILD_TYPE} Debug Release RelWithDebInfo MinSizeRel)
521        string(TOLOWER "${_build_type}" _build_type_lower)
522        string(TOUPPER "${_build_type}" _build_type_upper)
523        set_property(TARGET expat PROPERTY "pkgconfig_${_build_type_lower}_name" "expat${EXPAT_${_build_type_upper}_POSTFIX}")
524        set_property(TARGET expat PROPERTY "pkgconfig_${_build_type_lower}_output_name" "${_EXPAT_OUTPUT_NAME}${EXPAT_${_build_type_upper}_POSTFIX}")
525        if(_EXPAT_LIBM_FOUND)
526            set_property(TARGET expat PROPERTY "pkgconfig_libm" "-lm")
527        else()
528            set_property(TARGET expat PROPERTY "pkgconfig_libm" "")
529        endif()
530    endforeach()
531
532    file(GENERATE
533        OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/expat.pc
534        INPUT ${PROJECT_SOURCE_DIR}/expat.pc.cmake)
535
536    expat_install(FILES ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/expat.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
537endif()
538
539#
540# C command line tool xmlwf
541#
542if(EXPAT_BUILD_TOOLS)
543    set(xmlwf_SRCS
544        xmlwf/xmlwf.c
545        xmlwf/xmlfile.c
546        xmlwf/codepage.c
547        xmlwf/readfilemap.c
548    )
549
550    add_executable(xmlwf ${xmlwf_SRCS})
551    set_property(TARGET xmlwf PROPERTY RUNTIME_OUTPUT_DIRECTORY xmlwf)
552    target_link_libraries(xmlwf expat)
553    if(_EXPAT_LIBM_FOUND)
554        target_link_libraries(xmlwf m)
555    endif()
556    expat_install(TARGETS xmlwf DESTINATION ${CMAKE_INSTALL_BINDIR})
557
558    if(MINGW AND _EXPAT_UNICODE_WCHAR_T)
559        # https://gcc.gnu.org/onlinedocs/gcc/x86-Windows-Options.html
560        set_target_properties(xmlwf PROPERTIES LINK_FLAGS -municode)
561    endif()
562
563    if(EXPAT_BUILD_DOCS)
564        file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/doc)
565        add_custom_target(
566            xmlwf-manpage
567            COMMAND
568                "${DOCBOOK_TO_MAN}" "${PROJECT_SOURCE_DIR}/doc/xmlwf.xml" && mv "XMLWF.1" "${PROJECT_BINARY_DIR}/doc/xmlwf.1"
569            BYPRODUCTS
570                doc/xmlwf.1)
571        add_dependencies(expat xmlwf-manpage)
572        expat_install(FILES "${PROJECT_BINARY_DIR}/doc/xmlwf.1" DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
573    elseif(EXISTS ${PROJECT_SOURCE_DIR}/doc/xmlwf.1)
574        expat_install(FILES "${PROJECT_SOURCE_DIR}/doc/xmlwf.1" DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
575    endif()
576endif()
577
578#
579# C code examples
580#
581if(EXPAT_BUILD_EXAMPLES)
582    add_executable(elements examples/elements.c)
583    add_executable(outline examples/outline.c)
584
585    foreach(_target elements outline)
586        set_property(TARGET ${_target} PROPERTY RUNTIME_OUTPUT_DIRECTORY examples)
587        target_link_libraries(${_target} expat)
588    endforeach()
589endif()
590
591#
592# C/C++ test runners
593#
594if(EXPAT_BUILD_TESTS)
595    ## these are unittests that can be run on any platform
596    enable_testing()
597
598    set(test_SRCS
599        tests/chardata.c
600        tests/memcheck.c
601        tests/minicheck.c
602        tests/structdata.c
603        ${_EXPAT_C_SOURCES}
604    )
605
606    if(NOT MSVC)
607        if(MINGW)
608            set(host whatever-mingw32)  # for nothing but run.sh
609        endif()
610        configure_file(${CMAKE_CURRENT_SOURCE_DIR}/run.sh.in run.sh @ONLY)
611    endif()
612
613    function(expat_add_test _name _file)
614        if(MSVC)
615            add_test(NAME ${_name} COMMAND ${_file})
616        else()
617            add_test(NAME ${_name} COMMAND bash run.sh ${_file})
618        endif()
619    endfunction()
620
621    set(_EXPAT_TEST_TARGETS runtests runtestspp)
622    add_executable(runtests   tests/runtests.c     ${test_SRCS})
623    add_executable(runtestspp tests/runtestspp.cpp ${test_SRCS})
624
625    foreach(_target ${_EXPAT_TEST_TARGETS})
626        set_property(TARGET ${_target} PROPERTY RUNTIME_OUTPUT_DIRECTORY tests)
627        expat_add_test(${_target} $<TARGET_FILE:${_target}>)
628
629        if(_EXPAT_LIBM_FOUND)
630            target_link_libraries(${_target} m)
631        endif()
632
633        if(EXPAT_WITH_LIBBSD)
634            target_link_libraries(${_target} ${LIB_BSD})
635        endif()
636    endforeach()
637endif()
638
639#
640# Fuzzers
641#
642if(EXPAT_BUILD_FUZZERS)
643    if(NOT "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
644        message(SEND_ERROR
645            "Building fuzz targets without Clang (but ${CMAKE_C_COMPILER_ID}) "
646            "is not supported. Please set "
647            "-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++.")
648    endif()
649
650    string(FIND "${CMAKE_C_FLAGS}" "-fsanitize" sanitizer_present)
651    if(${sanitizer_present} EQUAL "-1")
652        message(WARNING
653            "There was no sanitizer present when building the fuzz targets. "
654            "This is likely in error - consider adding "
655            "-DCMAKE_C_FLAGS='-fsanitize=<sanitizer>' and "
656            "-DCMAKE_CXX_FLAGS='-fsanitize=<sanitizer>' and "
657            "-DCMAKE_EXE_LINKER_FLAGS='-fsanitize=<sanitizer>' and "
658            "-DCMAKE_MODULE_LINKER_FLAGS='-fsanitize=<sanitizer>' and "
659            "-DCMAKE_SHARED_LINKER_FLAGS='-fsanitize=<sanitizer>' to your cmake "
660            "execution.")
661    endif()
662
663    if(EXPAT_OSSFUZZ_BUILD AND NOT DEFINED ENV{LIB_FUZZING_ENGINE})
664        message(SEND_ERROR
665            "OSS-Fuzz builds require the environment variable "
666            "LIB_FUZZING_ENGINE to be set. If you are seeing this "
667            "warning, it points to a deeper problem in the ossfuzz "
668            "build setup.")
669    endif()
670
671    set(encoding_types UTF-16 UTF-8 ISO-8859-1 US-ASCII UTF-16BE UTF-16LE)
672    set(fuzz_targets xml_parse_fuzzer xml_parsebuffer_fuzzer)
673
674    add_library(fuzzpat STATIC ${_EXPAT_C_SOURCES})
675    if(NOT EXPAT_OSSFUZZ_BUILD)
676        target_compile_options(fuzzpat PRIVATE -fsanitize=fuzzer-no-link)
677    endif()
678
679    foreach(fuzz_target ${fuzz_targets})
680        foreach(encoding_type ${encoding_types})
681            set(target_name ${fuzz_target}_${encoding_type})
682            add_executable(${target_name} fuzz/${fuzz_target}.c)
683            target_link_libraries(${target_name} fuzzpat)
684            target_compile_definitions(${target_name}
685                PRIVATE ENCODING_FOR_FUZZING=${encoding_type})
686            if(NOT EXPAT_OSSFUZZ_BUILD)
687                target_compile_options(${target_name} PRIVATE -fsanitize=fuzzer-no-link)
688            endif()
689            # NOTE: Avoiding target_link_options here only because it needs CMake >=3.13
690            if(EXPAT_OSSFUZZ_BUILD)
691                set_target_properties(${target_name} PROPERTIES LINK_FLAGS $ENV{LIB_FUZZING_ENGINE})
692                set_target_properties(${target_name} PROPERTIES LINKER_LANGUAGE "CXX")
693            else()
694                set_target_properties(${target_name} PROPERTIES LINK_FLAGS -fsanitize=fuzzer)
695            endif()
696            set_property(
697                TARGET ${target_name} PROPERTY RUNTIME_OUTPUT_DIRECTORY fuzz)
698        endforeach()
699    endforeach()
700else()
701    if(EXPAT_OSSFUZZ_BUILD)
702        message(SEND_ERROR
703                "Attempting to perform an ossfuzz build without turning on the fuzzer build. "
704                "This is likely in error - consider adding "
705                "-DEXPAT_BUILD_FUZZERS=ON to your cmake execution.")
706    endif()
707endif()
708
709#
710# C/C++ config affecting multiple targets
711#
712if(WIN32)
713    set(_EXPAT_STATIC_TARGETS ${_EXPAT_TEST_TARGETS})
714    if(NOT EXPAT_SHARED_LIBS)
715        list(APPEND _EXPAT_STATIC_TARGETS expat)
716    endif()
717    if(EXPAT_BUILD_FUZZERS)
718        list(APPEND _EXPAT_STATIC_TARGETS fuzzpat)
719    endif()
720
721    foreach(_target ${_EXPAT_STATIC_TARGETS})
722        target_compile_definitions(${_target} PUBLIC -DXML_STATIC)
723    endforeach()
724endif()
725
726#
727# Custom target "run-xmltest"
728#
729if(EXPAT_BUILD_TOOLS AND NOT MSVC)
730    add_custom_target(
731        xmlts-zip-downloaded
732        COMMAND
733            sh -c 'test -f xmlts.zip || wget --output-document=xmlts.zip https://www.w3.org/XML/Test/xmlts20080827.zip'
734        BYPRODUCTS
735            tests/xmlts.zip
736        WORKING_DIRECTORY
737            tests/)
738
739    add_custom_target(
740        xmlts-zip-extracted
741        COMMAND
742            sh -c 'test -d xmlconf || unzip -q xmlts.zip'
743        BYPRODUCTS
744            tests/xmlconf
745        WORKING_DIRECTORY
746            tests/)
747    add_dependencies(xmlts-zip-extracted xmlts-zip-downloaded)
748
749    add_custom_target(
750        xmltest-sh-been-run
751        COMMAND
752            sh -c '${CMAKE_CURRENT_SOURCE_DIR}/tests/xmltest.sh "bash ${CMAKE_CURRENT_BINARY_DIR}/run.sh $<TARGET_FILE:xmlwf>" 2>&1 | tee tests/xmltest.log'
753        BYPRODUCTS
754            tests/xmltest.log)
755    add_dependencies(xmltest-sh-been-run xmlts-zip-extracted xmlwf)
756
757    add_custom_target(
758        xmltest-log-fixed
759        COMMAND
760            ${CMAKE_CURRENT_SOURCE_DIR}/fix-xmltest-log.sh tests/xmltest.log
761        DEPENDS
762            tests/xmltest.log)
763    add_dependencies(xmltest-log-fixed xmltest-sh-been-run)
764
765    add_custom_target(
766        xmltest-log-verified
767        COMMAND
768            diff -u ${CMAKE_CURRENT_SOURCE_DIR}/tests/xmltest.log.expected tests/xmltest.log)
769    add_dependencies(xmltest-log-verified xmltest-log-fixed)
770
771    add_custom_target(run-xmltest)
772    add_dependencies(run-xmltest xmltest-log-verified)
773endif()
774
775#
776# Documentation
777#
778configure_file(Changes changelog COPYONLY)
779expat_install(
780    FILES
781        AUTHORS
782        ${CMAKE_CURRENT_BINARY_DIR}/changelog
783    DESTINATION
784        ${CMAKE_INSTALL_DOCDIR})
785
786#
787# CMake files for find_package(expat [..] CONFIG [..])
788#
789configure_package_config_file(
790        cmake/expat-config.cmake.in
791        cmake/expat-config.cmake
792    INSTALL_DESTINATION
793        ${CMAKE_INSTALL_LIBDIR}/cmake/expat-${PROJECT_VERSION}/
794)
795write_basic_package_version_file(
796    cmake/expat-config-version.cmake
797    COMPATIBILITY SameMajorVersion  # i.e. semver
798)
799export(
800    TARGETS
801        expat
802    FILE
803        cmake/expat-targets.cmake  # not going to be installed
804)
805expat_install(
806    FILES
807        ${CMAKE_CURRENT_BINARY_DIR}/cmake/expat-config.cmake
808        ${CMAKE_CURRENT_BINARY_DIR}/cmake/expat-config-version.cmake
809    DESTINATION
810        ${CMAKE_INSTALL_LIBDIR}/cmake/expat-${PROJECT_VERSION}/
811)
812expat_install(
813    EXPORT
814        expat
815    DESTINATION
816        ${CMAKE_INSTALL_LIBDIR}/cmake/expat-${PROJECT_VERSION}/
817    NAMESPACE
818        expat::
819)
820
821#
822# CPack
823#
824
825# This effectively disables target "package_source".
826# That is done due to CPack's unfortunate choice of an exclusion list
827# rather than inclusion list.  An exclusion list does not protect against
828# unwanted files ending up in the resulting archive in a way that's
829# safe to run from an Expat developer's machine.
830set(CPACK_SOURCE_GENERATOR '')
831
832if(WIN32)
833    set(CPACK_GENERATOR ZIP)
834else()
835    set(CPACK_GENERATOR TGZ)
836endif()
837
838include(CPack)
839
840#
841# Summary
842#
843if(EXPAT_CHAR_TYPE STREQUAL "char")
844    set(_EXPAT_CHAR_TYPE_SUMMARY "char (UTF-8)")
845elseif(EXPAT_CHAR_TYPE STREQUAL "ushort")
846    set(_EXPAT_CHAR_TYPE_SUMMARY "ushort (unsigned short, UTF-16)")
847elseif(EXPAT_CHAR_TYPE STREQUAL "wchar_t")
848    if(WIN32)
849        set(_EXPAT_CHAR_TYPE_SUMMARY "wchar_t (UTF-16)")
850    else()
851        set(_EXPAT_CHAR_TYPE_SUMMARY "wchar_t (UTF-32)  // not implemented")
852    endif()
853else()
854    set(_EXPAT_CHAR_TYPE_SUMMARY "ERROR")
855endif()
856# NOTE: We're not accessing global property GENERATOR_IS_MULTI_CONFIG
857#       because that would require CMake >=3.9
858if(CMAKE_CONFIGURATION_TYPES)
859    set(_EXPAT_GENERATOR_IS_MULTI_CONFIG TRUE)
860else()
861    set(_EXPAT_GENERATOR_IS_MULTI_CONFIG FALSE)
862endif()
863
864message(STATUS "===========================================================================")
865message(STATUS "")
866message(STATUS "Configuration")
867message(STATUS "  Generator .................. ${CMAKE_GENERATOR}")
868if(_EXPAT_GENERATOR_IS_MULTI_CONFIG)
869    message(STATUS "  Build types ................ ${CMAKE_CONFIGURATION_TYPES}")
870else()
871    message(STATUS "  Build type ................. ${CMAKE_BUILD_TYPE}")
872endif()
873message(STATUS "  Prefix ..................... ${CMAKE_INSTALL_PREFIX}")
874message(STATUS "  Shared libraries ........... ${EXPAT_SHARED_LIBS}")
875if(MSVC)
876    message(STATUS "  Static CRT ................. ${EXPAT_MSVC_STATIC_CRT}")
877endif()
878message(STATUS "  Character type ............. ${_EXPAT_CHAR_TYPE_SUMMARY}")
879if(NOT _EXPAT_GENERATOR_IS_MULTI_CONFIG)
880    message(STATUS "  Library name postfix ....... ${EXPAT_${_EXPAT_BUILD_TYPE_UPPER}_POSTFIX}")
881endif()
882message(STATUS "")
883message(STATUS "  Build documentation ........ ${EXPAT_BUILD_DOCS}")
884message(STATUS "  Build examples ............. ${EXPAT_BUILD_EXAMPLES}")
885message(STATUS "  Build fuzzers .............. ${EXPAT_BUILD_FUZZERS}")
886message(STATUS "  Build tests ................ ${EXPAT_BUILD_TESTS}")
887message(STATUS "  Build tools (xmlwf) ........ ${EXPAT_BUILD_TOOLS}")
888message(STATUS "  Build pkg-config file ...... ${EXPAT_BUILD_PKGCONFIG}")
889message(STATUS "  Install files .............. ${EXPAT_ENABLE_INSTALL}")
890message(STATUS "")
891message(STATUS "  Features")
892message(STATUS "    // Advanced options, changes not advised")
893message(STATUS "    Attributes info .......... ${EXPAT_ATTR_INFO}")
894message(STATUS "    Context bytes ............ ${EXPAT_CONTEXT_BYTES}")
895message(STATUS "    DTD support .............. ${EXPAT_DTD}")
896message(STATUS "    Large size ............... ${EXPAT_LARGE_SIZE}")
897message(STATUS "    Minimum size ............. ${EXPAT_MIN_SIZE}")
898message(STATUS "    Namespace support ........ ${EXPAT_NS}")
899message(STATUS "")
900message(STATUS "  Entropy sources")
901if(WIN32)
902    message(STATUS "    rand_s ................... ON")
903else()
904    message(STATUS "    getrandom ................ ${HAVE_GETRANDOM}")
905    message(STATUS "    syscall SYS_getrandom .... ${HAVE_SYSCALL_GETRANDOM}")
906    message(STATUS "    libbsd ................... ${EXPAT_WITH_LIBBSD}")
907    message(STATUS "    /dev/random .............. ${EXPAT_DEV_URANDOM}")
908endif()
909message(STATUS "")
910if(CMAKE_GENERATOR STREQUAL "Unix Makefiles")
911    message(STATUS "Continue with")
912    message(STATUS "  make")
913    if(EXPAT_BUILD_TESTS)
914        message(STATUS "  make test")
915    endif()
916    if(EXPAT_ENABLE_INSTALL)
917        message(STATUS "  sudo make install")
918    endif()
919    message(STATUS "")
920endif()
921message(STATUS "===========================================================================")
922