diff --git a/CMakeLists.txt b/CMakeLists.txt index c1a443a4..868c899c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,8 +21,8 @@ include(cmake/functional.cmake) include(cmake/h5fortran.cmake) include(cmake/json.cmake) -# library to archive (libneural.a) -add_library(neural +# library to archive (libneural-fortran.a) +add_library(neural-fortran src/nf.f90 src/nf/nf_activation.f90 src/nf/nf_base_layer.f90 @@ -64,14 +64,14 @@ add_library(neural src/nf/io/nf_io_hdf5_submodule.f90 ) -target_link_libraries(neural PRIVATE +target_link_libraries(neural-fortran PRIVATE functional::functional h5fortran::h5fortran HDF5::HDF5 jsonfortran::jsonfortran ) -install(TARGETS neural) +install(TARGETS neural-fortran) # Remove leading or trailing whitespace string(REGEX REPLACE "^ | $" "" LIBS "${LIBS}") diff --git a/README.md b/README.md index a43d8a48..2b05e563 100644 --- a/README.md +++ b/README.md @@ -203,6 +203,23 @@ ctest to run the tests. +## Using neural-fortran in your project + +You can use the CMake module available [here](cmake/Findneural-fortran.cmake) to +find or fetch an installation of this project while configuring your project. This +module makes sure that the `neural-fortran::neural-fortran` target is always generated regardless +of how the neural-fortran is included in the project. + +You can configure neural-fortran by setting the appropriate options before +including the subproject. + +The following should be added in the CMake file of your directory: +```cmake +if(NOT TARGET "neural-fortran::neural-fortran") + find_package("neural-fortran" REQUIRED) +endif() +``` + ## Examples The easiest way to get a sense of how to use neural-fortran is to look at diff --git a/cmake/Findneural-fortran.cmake b/cmake/Findneural-fortran.cmake new file mode 100644 index 00000000..4fe87213 --- /dev/null +++ b/cmake/Findneural-fortran.cmake @@ -0,0 +1,179 @@ +# SPDX-Identifier: MIT +# Based on https://github.com/fortran-lang/stdlib-cmake-example + +#[[.rst: +Find neural-fortran +------------------- + +Makes the neural-fortran library project available. + +Imported Targets +^^^^^^^^^^^^^^^^ + +This module provides the following imported target, if found: + +``neural-fortran::neural-fortran`` + The neural-fortran library + + +Result Variables +^^^^^^^^^^^^^^^^ + +This module will define the following variables: + +``NEURAL-FORTRAN_FOUND`` + True if the neural-fortran library is available + +``NEURAL-FORTRAN_SOURCE_DIR`` + Path to the source directory of the neural-fortran library project, + only set if the project is included as source. + +``NEURAL-FORTRAN_BINARY_DIR`` + Path to the binary directory of the neural-fortran library project, + only set if the project is included as source. + +Cache variables +^^^^^^^^^^^^^^^ + +The following cache variables may be set to influence the library detection: + +``NEURAL-FORTRAN_FIND_METHOD`` + Methods to find or make the project available. Available methods are + - ``cmake``: Try to find via CMake config file + - ``pkgconf``: Try to find via pkg-config file + - ``subproject``: Use source in subprojects directory + - ``fetch``: Fetch the source from upstream + +``NEURAL-FORTRAN_DIR`` + Used for searching the CMake config file + +``NEURAL-FORTRAN_SUBPROJECT`` +Directory to find the neural-fortran library subproject, relative to the project root + +#]] + +set(_lib "neural-fortran") +set(_pkg "NEURAL-FORTRAN") +set(_url "https://github.com/modern-fortran/neural-fortran.git") + +if(NOT DEFINED "${_pkg}_FIND_METHOD") + if(DEFINED "${PROJECT_NAME}-dependency-method") + set("${_pkg}_FIND_METHOD" "${${PROJECT_NAME}-dependency-method}") + else() + set("${_pkg}_FIND_METHOD" "cmake" "pkgconf" "subproject" "fetch") + endif() + set("_${_pkg}_FIND_METHOD") +endif() + +foreach(method ${${_pkg}_FIND_METHOD}) + if(TARGET "${_lib}::${_lib}") + break() + endif() + + if("${method}" STREQUAL "cmake") + message(STATUS "${_lib}: Find installed package") + if(DEFINED "${_pkg}_DIR") + set("_${_pkg}_DIR") + set("${_lib}_DIR" "${_pkg}_DIR") + endif() + find_package("${_lib}" CONFIG) + if("${_lib}_FOUND") + message(STATUS "${_lib}: Found installed package") + break() + endif() + endif() + + if("${method}" STREQUAL "pkgconf") + find_package(PkgConfig QUIET) + pkg_check_modules("${_pkg}" QUIET "${_lib}") + if("${_pkg}_FOUND") + message(STATUS "Found ${_lib} via pkg-config") + + add_library("${_lib}::${_lib}" INTERFACE IMPORTED) + target_link_libraries( + "${_lib}::${_lib}" + INTERFACE + "${${_pkg}_LINK_LIBRARIES}" + ) + target_include_directories( + "${_lib}::${_lib}" + INTERFACE + "${${_pkg}_INCLUDE_DIRS}" + ) + + break() + endif() + endif() + + if("${method}" STREQUAL "subproject") + if(NOT DEFINED "${_pkg}_SUBPROJECT") + set("_${_pkg}_SUBPROJECT") + set("${_pkg}_SUBPROJECT" "subprojects/${_lib}") + endif() + set("${_pkg}_SOURCE_DIR" "${PROJECT_SOURCE_DIR}/${${_pkg}_SUBPROJECT}") + set("${_pkg}_BINARY_DIR" "${PROJECT_BINARY_DIR}/${${_pkg}_SUBPROJECT}") + if(EXISTS "${${_pkg}_SOURCE_DIR}/CMakeLists.txt") + message(STATUS "Include ${_lib} from ${${_pkg}_SUBPROJECT}") + add_subdirectory( + "${${_pkg}_SOURCE_DIR}" + "${${_pkg}_BINARY_DIR}" + ) + + add_library("${_lib}::${_lib}" INTERFACE IMPORTED) + target_link_libraries("${_lib}::${_lib}" INTERFACE "${_lib}") + + # We need the module directory in the subproject before we finish the configure stage + if(NOT EXISTS "${${_pkg}_BINARY_DIR}/mod_files") + make_directory("${${_pkg}_BINARY_DIR}/mod_files") + endif() + + break() + endif() + endif() + + if("${method}" STREQUAL "fetch") + message(STATUS "Retrieving ${_lib} from ${_url}") + include(FetchContent) + FetchContent_Declare( + "${_lib}" + GIT_REPOSITORY "${_url}" + GIT_TAG "HEAD" + ) + FetchContent_MakeAvailable("${_lib}") + + add_library("${_lib}::${_lib}" INTERFACE IMPORTED) + target_link_libraries("${_lib}::${_lib}" INTERFACE "${_lib}") + + # We need the module directory in the subproject before we finish the configure stage + FetchContent_GetProperties("${_lib}" SOURCE_DIR "${_pkg}_SOURCE_DIR") + FetchContent_GetProperties("${_lib}" BINARY_DIR "${_pkg}_BINARY_DIR") + if(NOT EXISTS "${${_pkg}_BINARY_DIR}/mod_files") + make_directory("${${_pkg}_BINARY_DIR}/mod_files") + endif() + + break() + endif() + +endforeach() + +if(TARGET "${_lib}::${_lib}") + set("${_pkg}_FOUND" TRUE) +else() + set("${_pkg}_FOUND" FALSE) +endif() + +if(DEFINED "_${_pkg}_SUBPROJECT") + unset("${_pkg}_SUBPROJECT") + unset("_${_pkg}_SUBPROJECT") +endif() +if(DEFINED "_${_pkg}_DIR") + unset("${_lib}_DIR") + unset("_${_pkg}_DIR") +endif() +if(DEFINED "_${_pkg}_FIND_METHOD") + unset("${_pkg}_FIND_METHOD") + unset("_${_pkg}_FIND_METHOD") +endif() +unset(_lib) +unset(_pkg) +unset(_url) diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index bded8d9c..48bcc91e 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -11,7 +11,7 @@ foreach(execid ) add_executable(${execid} ${execid}.f90) target_link_libraries(${execid} PRIVATE - neural + neural-fortran h5fortran::h5fortran jsonfortran::jsonfortran ${LIBS} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b24262c1..6903deb7 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -19,7 +19,7 @@ foreach(execid loss ) add_executable(test_${execid} test_${execid}.f90) - target_link_libraries(test_${execid} PRIVATE neural h5fortran::h5fortran jsonfortran::jsonfortran ${LIBS}) + target_link_libraries(test_${execid} PRIVATE neural-fortran h5fortran::h5fortran jsonfortran::jsonfortran ${LIBS}) add_test(NAME test_${execid} COMMAND test_${execid}) endforeach()