ADD_LIBRARY(JFJochStructureRefinement STATIC
        ModelFFT.cpp ModelFFT.h
        ModelGrid.cpp ModelGrid.h
        ModelScaling.cpp ModelScaling.h
        MolecularReplacement.cpp MolecularReplacement.h
        $<$<BOOL:${JFJOCH_CUDA_AVAILABLE}>:MolecularReplacementGPU.cu> MolecularReplacementGPU.h
        ModelValidation.cpp ModelValidation.h
        RugnuxModel.h
        RigidBodyRefine.cpp RigidBodyRefine.h
        $<$<BOOL:${JFJOCH_CUDA_AVAILABLE}>:RigidBodyGPU.cpp>
        $<$<BOOL:${JFJOCH_CUDA_AVAILABLE}>:RigidBodyGPU.cu>
        RigidBodyGPU.h RigidBodyGPUEngine.h
        $<$<BOOL:${JFJOCH_CUDA_AVAILABLE}>:ModelDensityGPU.cu> ModelDensityGPU.h
        $<$<BOOL:${JFJOCH_CUDA_AVAILABLE}>:ModelMaskGPU.cu> ModelMaskGPU.h
        $<$<BOOL:${JFJOCH_CUDA_AVAILABLE}>:ModelStructureFactorsGPU.cpp>
        $<$<BOOL:${JFJOCH_CUDA_AVAILABLE}>:ModelStructureFactorsGPU.cu>
        ModelStructureFactorsGPU.h ModelStructureFactorsGPUEngine.h
        $<$<BOOL:${JFJOCH_CUDA_AVAILABLE}>:ModelScaleGPU.cu> ModelScaleGPU.h
        SigmaA.cpp SigmaA.h
        MonomerLibrary.cpp MonomerLibrary.h
        RefinementMath.h RefinementMinimiser.h
        RefinementRestraints.cpp RefinementRestraints.h
        RefinementXray.cpp RefinementXray.h
        Refinement.cpp Refinement.h
        DensityBlobs.cpp DensityBlobs.h
        $<$<BOOL:${JFJOCH_CUDA_AVAILABLE}>:RefinementGPU.cpp>
        $<$<BOOL:${JFJOCH_CUDA_AVAILABLE}>:RefinementGPU.cu>
        RefinementGPU.h RefinementGPUEngine.h
        ${CMAKE_CURRENT_BINARY_DIR}/MonomerLibraryData.cpp)

# The subset of the CCP4 Monomer Library that refinement restrains with (monomers/, chosen by
# monomers/update_monomers.py), carried in the binary so that nothing is read from disk: every .cif of the
# directory as a string, cut into pieces of at most 12000 characters - under the 16380 a single literal may
# hold with MSVC - which MonomerLibrary.cpp joins again. A .cif added or edited re-runs the configure.
FILE(GLOB MONOMER_CIFS ${CMAKE_CURRENT_SOURCE_DIR}/monomers/*.cif)
SET_PROPERTY(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${MONOMER_CIFS} ${CMAKE_CURRENT_SOURCE_DIR}/monomers)
SET(monomer_source "// Generated from image_analysis/structure_refinement/monomers by its CMakeLists.txt - do not edit.\n")
STRING(APPEND monomer_source "#include \"MonomerLibrary.h\"\n\n")
SET(monomer_table "")
SET(monomer_count 0)
FOREACH(cif ${MONOMER_CIFS})
    GET_FILENAME_COMPONENT(cif_name ${cif} NAME)
    FILE(READ ${cif} text)
    STRING(LENGTH "${text}" text_length)
    SET(pieces "")
    SET(n_pieces 0)
    SET(offset 0)
    WHILE(offset LESS text_length)
        STRING(SUBSTRING "${text}" ${offset} 12000 piece)
        STRING(APPEND pieces "R\"MONLIB(${piece})MONLIB\",\n")
        MATH(EXPR offset "${offset} + 12000")
        MATH(EXPR n_pieces "${n_pieces} + 1")
    ENDWHILE()
    STRING(APPEND monomer_source "static const char *const file_${monomer_count}[] = {\n${pieces}};\n")
    STRING(APPEND monomer_table "    {\"${cif_name}\", file_${monomer_count}, ${n_pieces}},\n")
    MATH(EXPR monomer_count "${monomer_count} + 1")
ENDFOREACH()
STRING(APPEND monomer_source "\nextern const EmbeddedMonomerFile embedded_monomer_files[] = {\n${monomer_table}};\n")
STRING(APPEND monomer_source "extern const size_t embedded_monomer_file_count = ${monomer_count};\n")
# Written only when it changed, so a configure does not rebuild the library.
FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/MonomerLibraryData.cpp.tmp "${monomer_source}")
CONFIGURE_FILE(${CMAKE_CURRENT_BINARY_DIR}/MonomerLibraryData.cpp.tmp
               ${CMAKE_CURRENT_BINARY_DIR}/MonomerLibraryData.cpp COPYONLY)
TARGET_INCLUDE_DIRECTORIES(JFJochStructureRefinement PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})

# JFJochIndexing for CUDAMemHelpers.h and, under CUDA, to put cuFFT (RigidBodyGPU.cu) after these
# objects on the link line.
TARGET_LINK_LIBRARIES(JFJochStructureRefinement JFJochScaleMerge JFJochIndexing JFJochCommon gemmi fftw3f)

IF (APPLE)
    # The rotation function on the Apple GPU (MolecularReplacementMetal.h). Its kernel is compiled when it is first
    # used, from source carried in the binary, as image_analysis/bragg_integration does: the .metal file copied into
    # a generated .cpp here; editing it re-runs the configure.
    FILE(READ ${CMAKE_CURRENT_SOURCE_DIR}/MolecularReplacementMetal.metal text)
    SET_PROPERTY(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/MolecularReplacementMetal.metal)
    # Written only when it changed, so a configure does not rebuild the library.
    FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/MolecularReplacementMetalSource.cpp.tmp
         "// Generated from image_analysis/structure_refinement by its CMakeLists.txt - do not edit.\n"
         "extern const char *const mr_metal_source;\n"
         "const char *const mr_metal_source = R\"MR_METAL(\n${text})MR_METAL\";\n")
    CONFIGURE_FILE(${CMAKE_CURRENT_BINARY_DIR}/MolecularReplacementMetalSource.cpp.tmp
                   ${CMAKE_CURRENT_BINARY_DIR}/MolecularReplacementMetalSource.cpp COPYONLY)
    TARGET_SOURCES(JFJochStructureRefinement PRIVATE MolecularReplacementMetal.mm MolecularReplacementMetal.h
            MolecularReplacementMetal.metal ${CMAKE_CURRENT_BINARY_DIR}/MolecularReplacementMetalSource.cpp)
    SET_SOURCE_FILES_PROPERTIES(MolecularReplacementMetal.mm PROPERTIES COMPILE_OPTIONS -fobjc-arc)
    SET_SOURCE_FILES_PROPERTIES(MolecularReplacementMetal.metal PROPERTIES HEADER_FILE_ONLY ON)
    # The model density's gather (ModelDensityMetal.h), carried in the same way.
    FILE(READ ${CMAKE_CURRENT_SOURCE_DIR}/ModelDensityMetal.metal text)
    SET_PROPERTY(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ModelDensityMetal.metal)
    FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/ModelDensityMetalSource.cpp.tmp
         "// Generated from image_analysis/structure_refinement by its CMakeLists.txt - do not edit.\n"
         "extern const char *const model_density_metal_source;\n"
         "const char *const model_density_metal_source = R\"DENSITY_METAL(\n${text})DENSITY_METAL\";\n")
    CONFIGURE_FILE(${CMAKE_CURRENT_BINARY_DIR}/ModelDensityMetalSource.cpp.tmp
                   ${CMAKE_CURRENT_BINARY_DIR}/ModelDensityMetalSource.cpp COPYONLY)
    TARGET_SOURCES(JFJochStructureRefinement PRIVATE ModelDensityMetal.mm ModelDensityMetal.h
            ModelDensityMetal.metal ${CMAKE_CURRENT_BINARY_DIR}/ModelDensityMetalSource.cpp)
    SET_SOURCE_FILES_PROPERTIES(ModelDensityMetal.mm PROPERTIES COMPILE_OPTIONS -fobjc-arc)
    SET_SOURCE_FILES_PROPERTIES(ModelDensityMetal.metal PROPERTIES HEADER_FILE_ONLY ON)
    TARGET_LINK_LIBRARIES(JFJochStructureRefinement "-framework Metal" "-framework Foundation")
ENDIF()
