cmake_minimum_required(VERSION 3.13)
cmake_policy(SET CMP0077 NEW)

project(libxml2 C)

set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR})

macro(libxml2_option optionName optionDesc optionDefault)
  # Define actual option, with LIBXML2_ prefix to avoid conflicts when the project is added
  # with add_subdirectory in a bigger project
  option(LIBXML2_${optionName} ${optionDesc} ${optionDefault})

  # Depending on the value of the CMake function, set the ${libxml2_option} CMake variable
  # to 1 or 0 for correctly generating the xmlversion.h file
  if(LIBXML2_${optionName})
    set(${optionName} 1)
  else()
    set(${optionName} 0)
  endif()
endmacro()

# Options with a direct autotool-equivalent
libxml2_option(WITH_C14N "add the Canonicalization support" ON)
libxml2_option(WITH_CATALOG "add the Catalog support" ON)
libxml2_option(WITH_DEBUG "add the debugging module" ON)
libxml2_option(WITH_DOCBOOK "add Docbook SGML support" ON)

# Define WITH_DOCB for compatibility with xmlversion.h.in
if(LIBXML2_WITH_DOCBOOK)
  set(WITH_DOCB 1)
else()
  set(WITH_DOCB 0)
endif()

libxml2_option(WITH_FEXCEPTIONS "add GCC flag -fexceptions for C++ exceptions" OFF)
libxml2_option(WITH_FTP "add the FTP support" ON)
libxml2_option(WITH_HISTORY "add history support to xmllint shell" OFF)
libxml2_option(WITH_HTML "add the HTML support" ON)
libxml2_option(WITH_HTTP "add the HTTP support" ON)
libxml2_option(WITH_ICONV "add ICONV support" ON)
libxml2_option(WITH_ICU "add ICU support" OFF)
libxml2_option(WITH_ISO8859X "add ISO8859X support if no iconv" ON)
libxml2_option(WITH_LEGACY "add deprecated APIs for compatibility" ON)
libxml2_option(WITH_MEM_DEBUG "add the memory debugging module" OFF)
libxml2_option(WITH_MINIMUM "build a minimally sized library" OFF)
libxml2_option(WITH_OUTPUT "add the serialization support" ON)
libxml2_option(WITH_PATTERN "add the xmlPattern selection interface" ON)
libxml2_option(WITH_PUSH "add the PUSH parser interfaces" ON)
libxml2_option(WITH_READER "add the xmlReader parsing interface" ON)
libxml2_option(WITH_REGEXPS "add Regular Expressions support" ON)
libxml2_option(WITH_RUN_DEBUG "add the runtime debugging module" OFF)
libxml2_option(WITH_SAX1 "add the older SAX1 interface" ON)
libxml2_option(WITH_SCHEMAS "add Relax-NG and Schemas support" ON)
libxml2_option(WITH_SCHEMATRON " add Schematron support " ON)
libxml2_option(WITH_THREADS "add multithread support" ON)
libxml2_option(WITH_THREAD_ALLOC "add per-thread memory" OFF)
libxml2_option(WITH_TREE "add the DOM like tree manipulation APIs" ON)
libxml2_option(WITH_VALID "add the DTD validation support" ON)
libxml2_option(WITH_WRITER "add the xmlWriter saving interface" ON)
libxml2_option(WITH_XINCLUDE "add the XInclude support" ON)
libxml2_option(WITH_XPATH "add the XPATH support" ON)
libxml2_option(WITH_XPTR "add the XPointer support" ON)
libxml2_option(WITH_MODULES "add the dynamic modules support" OFF)

# Option on dependencies
libxml2_option(WITH_ZLIB "add zlib support" ON)
libxml2_option(WITH_LZMA "add lzma support" OFF)
libxml2_option(WITH_TRIO "add trio support" OFF)

# Dependencies
if(WITH_ZLIB)
  find_package(ZLIB REQUIRED)
endif()

if(WITH_LZMA)
  find_package(LibLZMA REQUIRED)
endif()

if(WITH_ICU)
  find_package(ICU 61.0 COMPONENTS uc i18n data REQUIRED)
endif()

if(WITH_ICONV)
  find_package(Iconv REQUIRED)
endif()

if(WITH_THREADS)
  find_package(Threads REQUIRED)
endif()

# Copy platform headers in Windows, but generate it on other platforms
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
  configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/win32config.h ${CMAKE_CURRENT_BINARY_DIR}/config.h COPYONLY)
else()
  add_definitions("-DHAVE_CONFIG_H")
  set(ICONV_CONST "")
  # Generate config.h in  ${CMAKE_CURRENT_BINARY_DIR}
  # (see https://stackoverflow.com/questions/38419876/cmake-generate-config-h-like-from-autoconf )
  include(GenerateConfigHeader)
  if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
    add_definitions(
      "-Wall" "-Wextra" "-Wshadow" "-Wpointer-arith" "-Wcast-align" "-Wwrite-strings"
      "-Waggregate-return" "-Wstrict-prototypes" "-Wmissing-prototypes" "-Wnested-externs"
      "-Winline" "-Wredundant-decls" "-Wno-long-long" "-Wno-format-extra-args" "-Wno-array-bounds")
  endif()
endif()

# Glob public headers
file(GLOB xml2_public_headers ${CMAKE_CURRENT_SOURCE_DIR}/include/libxml/*.h)
file(COPY ${xml2_public_headers} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/libxml/)

# Generate xmlversion.h
set(VERSION "2.9.14")
set(LIBXML_VERSION_NUMBER "20914")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/libxml/xmlversion.h.in ${CMAKE_CURRENT_BINARY_DIR}/libxml/xmlversion.h)
list(APPEND xml2_public_headers ${CMAKE_CURRENT_BINARY_DIR}/libxml/xmlversion.h)

set(srcs ${CMAKE_CURRENT_SOURCE_DIR}/SAX.c
         ${CMAKE_CURRENT_SOURCE_DIR}/entities.c
         ${CMAKE_CURRENT_SOURCE_DIR}/encoding.c
         ${CMAKE_CURRENT_SOURCE_DIR}/error.c
         ${CMAKE_CURRENT_SOURCE_DIR}/parserInternals.c
         ${CMAKE_CURRENT_SOURCE_DIR}/parser.c
         ${CMAKE_CURRENT_SOURCE_DIR}/tree.c
         ${CMAKE_CURRENT_SOURCE_DIR}/hash.c
         ${CMAKE_CURRENT_SOURCE_DIR}/list.c
         ${CMAKE_CURRENT_SOURCE_DIR}/xmlIO.c
         ${CMAKE_CURRENT_SOURCE_DIR}/xmlmemory.c
         ${CMAKE_CURRENT_SOURCE_DIR}/uri.c
         ${CMAKE_CURRENT_SOURCE_DIR}/valid.c
         ${CMAKE_CURRENT_SOURCE_DIR}/xlink.c
         ${CMAKE_CURRENT_SOURCE_DIR}/HTMLparser.c
         ${CMAKE_CURRENT_SOURCE_DIR}/HTMLtree.c
         ${CMAKE_CURRENT_SOURCE_DIR}/debugXML.c
         ${CMAKE_CURRENT_SOURCE_DIR}/xpath.c
         ${CMAKE_CURRENT_SOURCE_DIR}/xpointer.c
         ${CMAKE_CURRENT_SOURCE_DIR}/xinclude.c
         ${CMAKE_CURRENT_SOURCE_DIR}/nanohttp.c
         ${CMAKE_CURRENT_SOURCE_DIR}/nanoftp.c
         ${CMAKE_CURRENT_SOURCE_DIR}/catalog.c
         ${CMAKE_CURRENT_SOURCE_DIR}/globals.c
         ${CMAKE_CURRENT_SOURCE_DIR}/threads.c
         ${CMAKE_CURRENT_SOURCE_DIR}/c14n.c
         ${CMAKE_CURRENT_SOURCE_DIR}/xmlstring.c
         ${CMAKE_CURRENT_SOURCE_DIR}/buf.c
         ${CMAKE_CURRENT_SOURCE_DIR}/xmlregexp.c
         ${CMAKE_CURRENT_SOURCE_DIR}/xmlschemas.c
         ${CMAKE_CURRENT_SOURCE_DIR}/xmlschemastypes.c
         ${CMAKE_CURRENT_SOURCE_DIR}/xmlunicode.c
         ${CMAKE_CURRENT_SOURCE_DIR}/xmlreader.c
         ${CMAKE_CURRENT_SOURCE_DIR}/relaxng.c
         ${CMAKE_CURRENT_SOURCE_DIR}/dict.c
         ${CMAKE_CURRENT_SOURCE_DIR}/SAX2.c
         ${CMAKE_CURRENT_SOURCE_DIR}/xmlwriter.c
         ${CMAKE_CURRENT_SOURCE_DIR}/legacy.c
         ${CMAKE_CURRENT_SOURCE_DIR}/chvalid.c
         ${CMAKE_CURRENT_SOURCE_DIR}/pattern.c
         ${CMAKE_CURRENT_SOURCE_DIR}/xmlsave.c
         ${CMAKE_CURRENT_SOURCE_DIR}/xmlmodule.c
         ${CMAKE_CURRENT_SOURCE_DIR}/schematron.c
         ${CMAKE_CURRENT_SOURCE_DIR}/xzlib.c)

if(NOT WITH_XPATH)
  list(REMOVE_ITEM xml2_public_headers ${CMAKE_CURRENT_SOURCE_DIR}/include/libxml/xpath.h)
  list(REMOVE_ITEM srcs ${CMAKE_CURRENT_SOURCE_DIR}/xpath.c)
endif()

if(NOT WITH_XPTR)
  list(REMOVE_ITEM xml2_public_headers ${CMAKE_CURRENT_SOURCE_DIR}/include/libxml/xpointer.h)
  list(REMOVE_ITEM srcs ${CMAKE_CURRENT_SOURCE_DIR}/xpointer.c)
endif()

if(NOT WITH_XINCLUDE)
  list(REMOVE_ITEM xml2_public_headers ${CMAKE_CURRENT_SOURCE_DIR}/include/libxml/xinclude.h)
  list(REMOVE_ITEM srcs ${CMAKE_CURRENT_SOURCE_DIR}/xinclude.c)
endif()

add_library(xml2 ${srcs})

target_include_directories(xml2 PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
                                       $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)

if(NOT BUILD_SHARED_LIBS)
  target_compile_definitions(xml2 PRIVATE -DLIBXML_STATIC)
  set(XML_CFLAGS "-DLIBXML_STATIC")
endif()

set(LIBS ${CMAKE_DL_LIBS})
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
  target_include_directories(xml2 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/win32/vc10)
  list(APPEND LIBS wsock32.lib ws2_32.lib)
  target_compile_definitions(xml2 PRIVATE -DHAVE_WIN32_THREADS)
elseif(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
  find_library (SOCKET socket REQUIRED)
  find_library (NSL nsl REQUIRED)
  list(APPEND LIBS m socket nsl)
else()
  list(APPEND LIBS m)
endif()
target_link_libraries(xml2 PRIVATE ${LIBS})

if(LIBXML2_WITH_ZLIB)
  target_link_libraries(xml2 PRIVATE ${ZLIB_LIBRARIES})
  target_include_directories(xml2 PRIVATE ${ZLIB_INCLUDE_DIRS})
  list(APPEND LIBS z)
endif()
if(LIBXML2_WITH_LZMA)
  target_link_libraries(xml2 PRIVATE ${LIBLZMA_LIBRARIES})
  target_include_directories(xml2 PRIVATE ${LIBLZMA_INCLUDE_DIRS})
  list(APPEND LIBS ${LIBLZMA_LIBRARIES})
endif()
if(LIBXML2_WITH_ICONV)
  target_link_libraries(xml2 PRIVATE ${Iconv_LIBRARIES})
  target_include_directories(xml2 PRIVATE ${Iconv_INCLUDE_DIRS})
  list(APPEND LIBS ${Iconv_LIBRARIES})
endif()
if(LIBXML2_WITH_ICU)
  target_link_libraries(xml2 PRIVATE ${ICU_LIBRARIES})
  target_include_directories(xml2 PRIVATE ${ICU_INCLUDE_DIRS})
  list(APPEND LIBS ${ICU_LIBRARIES})
endif()
if(LIBXML2_WITH_THREADS)
  target_link_libraries(xml2 PRIVATE ${CMAKE_THREAD_LIBS_INIT})
  target_compile_definitions(xml2 PRIVATE -D_REENTRANT)
  list(APPEND LIBS ${CMAKE_THREAD_LIBS_INIT})
endif()

# Public headers
set_target_properties(xml2 PROPERTIES PUBLIC_HEADER "${xml2_public_headers}")

if(NOT SKIP_INSTALL_ALL)
  include(GNUInstallDirs)
  install(TARGETS xml2
          EXPORT  ${PROJECT_NAME}
          LIBRARY       DESTINATION "${CMAKE_INSTALL_LIBDIR}"
          ARCHIVE       DESTINATION "${CMAKE_INSTALL_LIBDIR}"
          RUNTIME       DESTINATION "${CMAKE_INSTALL_BINDIR}"
          PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/libxml2/libxml")

  # Note that we do not install CMake imported targets, to remain compatible with
  # the libxml2 compiled by autotools: the generated libraries are expected to be
  # found by LibXml2.cmake available in cmake
  # However, for compatibility with the autotools build system we generate and install
  # the libxml2-config.cmake file
  string(REPLACE ";" " " LIBS "${LIBS}")
  configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libxml2-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/libxml2-config.cmake @ONLY)
  install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libxml2-config.cmake DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/libxml2")

  string(REPLACE " " " -l" LIBS " ${LIBS}")
	set(prefix "${CMAKE_INSTALL_PREFIX}")
  set(exec_prefix "\${prefix}")
  set(libdir "\${prefix}/${CMAKE_INSTALL_LIBDIR}")
  set(includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
  configure_file(libxml-2.0.pc.in.cmake libxml-2.0.pc @ONLY)
  install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libxml-2.0.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)

  # Add uninstall target
  configure_file(
    ${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in
    ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake IMMEDIATE @ONLY
  )

  add_custom_target(
    "uninstall"
    ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake
  )
endif()

