function(sourcemeta_library)
  cmake_parse_arguments(SOURCEMETA_LIBRARY ""
    "NAMESPACE;PROJECT;NAME;VARIANT" "PRIVATE_HEADERS;SOURCES" ${ARGN})

  if(NOT SOURCEMETA_LIBRARY_PROJECT)
    message(FATAL_ERROR "You must pass the project name using the PROJECT option")
  endif()
  if(NOT SOURCEMETA_LIBRARY_NAME)
    message(FATAL_ERROR "You must pass the library name using the NAME option")
  endif()

  if(SOURCEMETA_LIBRARY_NAMESPACE)
    set(INCLUDE_PREFIX "include/${SOURCEMETA_LIBRARY_NAMESPACE}/${SOURCEMETA_LIBRARY_PROJECT}")
  else()
    set(INCLUDE_PREFIX "include/${SOURCEMETA_LIBRARY_PROJECT}")
  endif()

  set(EXPORT_HEADER_PATH "${CMAKE_CURRENT_BINARY_DIR}/${INCLUDE_PREFIX}/${SOURCEMETA_LIBRARY_NAME}_export.h")
  if(NOT SOURCEMETA_LIBRARY_VARIANT)
    set(PUBLIC_HEADER "${INCLUDE_PREFIX}/${SOURCEMETA_LIBRARY_NAME}.h")
  else()
    set(PUBLIC_HEADER "../${INCLUDE_PREFIX}/${SOURCEMETA_LIBRARY_NAME}.h")
  endif()

  if(SOURCEMETA_LIBRARY_SOURCES)
    set(ABSOLUTE_PRIVATE_HEADERS "${EXPORT_HEADER_PATH}")
  else()
    set(ABSOLUTE_PRIVATE_HEADERS)
  endif()

  foreach(private_header IN LISTS SOURCEMETA_LIBRARY_PRIVATE_HEADERS)
    if(SOURCEMETA_LIBRARY_VARIANT)
      list(APPEND ABSOLUTE_PRIVATE_HEADERS "../${INCLUDE_PREFIX}/${SOURCEMETA_LIBRARY_NAME}_${private_header}")
    else()
      list(APPEND ABSOLUTE_PRIVATE_HEADERS "${INCLUDE_PREFIX}/${SOURCEMETA_LIBRARY_NAME}_${private_header}")
    endif()
  endforeach()

  if(SOURCEMETA_LIBRARY_NAMESPACE)
    set(TARGET_NAME "${SOURCEMETA_LIBRARY_NAMESPACE}_${SOURCEMETA_LIBRARY_PROJECT}_${SOURCEMETA_LIBRARY_NAME}")
    set(ALIAS_NAME "${SOURCEMETA_LIBRARY_NAMESPACE}::${SOURCEMETA_LIBRARY_PROJECT}::${SOURCEMETA_LIBRARY_NAME}")
    set(FOLDER_NAME "${SOURCEMETA_LIBRARY_NAMESPACE}/${SOURCEMETA_LIBRARY_PROJECT}/${SOURCEMETA_LIBRARY_NAME}")
  else()
    set(TARGET_NAME "${SOURCEMETA_LIBRARY_PROJECT}_${SOURCEMETA_LIBRARY_NAME}")
    set(ALIAS_NAME "${SOURCEMETA_LIBRARY_PROJECT}::${SOURCEMETA_LIBRARY_NAME}")
    set(FOLDER_NAME "${SOURCEMETA_LIBRARY_PROJECT}/${SOURCEMETA_LIBRARY_NAME}")
  endif()

  if(SOURCEMETA_LIBRARY_VARIANT)
    set(TARGET_NAME "${TARGET_NAME}_${SOURCEMETA_LIBRARY_VARIANT}")
    set(ALIAS_NAME "${ALIAS_NAME}::${SOURCEMETA_LIBRARY_VARIANT}")
  endif()

  if(SOURCEMETA_LIBRARY_SOURCES)
    add_library(${TARGET_NAME}
      ${PUBLIC_HEADER} ${ABSOLUTE_PRIVATE_HEADERS} ${SOURCEMETA_LIBRARY_SOURCES})
    sourcemeta_add_default_options(PRIVATE ${TARGET_NAME})
  else()
    add_library(${TARGET_NAME} INTERFACE
      ${PUBLIC_HEADER} ${ABSOLUTE_PRIVATE_HEADERS})
    sourcemeta_add_default_options(INTERFACE ${TARGET_NAME})
  endif()

  add_library(${ALIAS_NAME} ALIAS ${TARGET_NAME})

  if(NOT SOURCEMETA_LIBRARY_VARIANT)
    set(include_dir "${CMAKE_CURRENT_SOURCE_DIR}/include")
  else()
    set(include_dir "${CMAKE_CURRENT_SOURCE_DIR}/../include")
  endif()
  if(SOURCEMETA_LIBRARY_SOURCES)
    target_include_directories(${TARGET_NAME} PUBLIC
      "$<BUILD_INTERFACE:${include_dir}>"
      "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
  else()
    target_include_directories(${TARGET_NAME} INTERFACE
      "$<BUILD_INTERFACE:${include_dir}>"
      "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
  endif()

  if(SOURCEMETA_LIBRARY_VARIANT)
    set(export_name "${SOURCEMETA_LIBRARY_PROJECT}::${SOURCEMETA_LIBRARY_NAME}::${SOURCEMETA_LIBRARY_VARIANT}")
  else()
    set(export_name "${SOURCEMETA_LIBRARY_PROJECT}::${SOURCEMETA_LIBRARY_NAME}")
  endif()

  if(SOURCEMETA_LIBRARY_SOURCES)
    set_target_properties(${TARGET_NAME}
      PROPERTIES
        OUTPUT_NAME ${TARGET_NAME}
        PUBLIC_HEADER "${PUBLIC_HEADER}"
        PRIVATE_HEADER "${ABSOLUTE_PRIVATE_HEADERS}"
        EXPORT_NAME "${export_name}"
        FOLDER "${FOLDER_NAME}")
  else()
    set_target_properties(${TARGET_NAME}
      PROPERTIES
        OUTPUT_NAME ${TARGET_NAME}
        PUBLIC_HEADER "${PUBLIC_HEADER}"
        PRIVATE_HEADER "${ABSOLUTE_PRIVATE_HEADERS}"
        EXPORT_NAME "${export_name}"
        FOLDER "${FOLDER_NAME}")
  endif()

  if(SOURCEMETA_LIBRARY_SOURCES)
    include(GenerateExportHeader)
    generate_export_header(${TARGET_NAME}
      EXPORT_FILE_NAME ${EXPORT_HEADER_PATH})
    set_target_properties(${TARGET_NAME}
      PROPERTIES
        SOVERSION "${PROJECT_VERSION_MAJOR}"
        VERSION "${PROJECT_VERSION}")

    # To find the generated files
    target_include_directories(${TARGET_NAME}
      PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>")
  endif()
endfunction()

function(sourcemeta_library_install)
  cmake_parse_arguments(SOURCEMETA_LIBRARY "" "NAMESPACE;PROJECT;NAME;VARIANT" "" ${ARGN})

  if(NOT SOURCEMETA_LIBRARY_PROJECT)
    message(FATAL_ERROR "You must pass the project name using the PROJECT option")
  endif()
  if(NOT SOURCEMETA_LIBRARY_NAME)
    message(FATAL_ERROR "You must pass the library name using the NAME option")
  endif()

  if(SOURCEMETA_LIBRARY_NAMESPACE)
    set(COMPONENT_NAME "${SOURCEMETA_LIBRARY_NAMESPACE}_${SOURCEMETA_LIBRARY_PROJECT}")
    set(TARGET_NAME "${SOURCEMETA_LIBRARY_NAMESPACE}_${SOURCEMETA_LIBRARY_PROJECT}_${SOURCEMETA_LIBRARY_NAME}")
    set(INCLUDE_PATH "${CMAKE_INSTALL_INCLUDEDIR}/${SOURCEMETA_LIBRARY_NAMESPACE}/${SOURCEMETA_LIBRARY_PROJECT}")
    set(NAMESPACE_PREFIX "${SOURCEMETA_LIBRARY_NAMESPACE}::")
  else()
    set(COMPONENT_NAME "${SOURCEMETA_LIBRARY_PROJECT}")
    set(TARGET_NAME "${SOURCEMETA_LIBRARY_PROJECT}_${SOURCEMETA_LIBRARY_NAME}")
    set(INCLUDE_PATH "${CMAKE_INSTALL_INCLUDEDIR}/${SOURCEMETA_LIBRARY_PROJECT}")
    set(NAMESPACE_PREFIX "")
  endif()

  if(SOURCEMETA_LIBRARY_VARIANT)
    set(TARGET_NAME "${TARGET_NAME}_${SOURCEMETA_LIBRARY_VARIANT}")
  endif()

  include(GNUInstallDirs)
  install(TARGETS ${TARGET_NAME}
    EXPORT ${TARGET_NAME}
    PUBLIC_HEADER DESTINATION "${INCLUDE_PATH}"
      COMPONENT ${COMPONENT_NAME}_dev
    PRIVATE_HEADER DESTINATION "${INCLUDE_PATH}"
      COMPONENT ${COMPONENT_NAME}_dev
    RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
      COMPONENT ${COMPONENT_NAME}
    LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
      COMPONENT ${COMPONENT_NAME}
      NAMELINK_COMPONENT ${COMPONENT_NAME}_dev
    ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
    COMPONENT ${COMPONENT_NAME}_dev)
  install(EXPORT ${TARGET_NAME}
    DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${SOURCEMETA_LIBRARY_PROJECT}"
    NAMESPACE ${NAMESPACE_PREFIX}
    COMPONENT ${COMPONENT_NAME}_dev)
endfunction()
