Skip to content

Commit

Permalink
Update for cmake use of neural-fortran (#192)
Browse files Browse the repository at this point in the history
* Update for cmake use of neural-fortran

* Update readme

* Fix up comment in cmake file

* Add CMakeLists.txt to CI

* Update cmake

* Remove -DSERIAL=1

* Remove -DSERIAL=1

---------

Co-authored-by: Milan Curcic <[email protected]>
  • Loading branch information
mathomp4 and milancurcic authored Sep 13, 2024
1 parent 9a40117 commit d516437
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 186 deletions.
14 changes: 10 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ on:
- ".github/workflows/ci.yml"
- "fpm.toml"
- "**.f90"
- "CMakelists.txt"

pull_request:
paths:
- ".github/workflows/ci.yml"
- "fpm.toml"
- "**.f90"
- "CMakelists.txt"

jobs:

Expand All @@ -21,20 +23,24 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: CMake Configure
run: cmake -B build -S . -DCMAKE_BUILD_TYPE=Debug
- name: Compile
run: cmake -DCMAKE_BUILD_TYPE=Debug -DSERIAL=1 . && make
run: cmake --build build
- name: Test
run: make test
run: ctest --test-dir build

gnu-cmake-release:
name: gnu-cmake-release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: CMake Configure
run: cmake -B build -S . -DCMAKE_BUILD_TYPE=Release
- name: Compile
run: cmake -DCMAKE_BUILD_TYPE=Release -DSERIAL=1 . && make
run: cmake --build build
- name: Test
run: make test
run: ctest --test-dir build

gnu-fpm-debug:
name: gnu-fpm-debug
Expand Down
9 changes: 9 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,25 @@ add_library(neural-fortran
)

target_link_libraries(neural-fortran PRIVATE)
set_target_properties(neural-fortran PROPERTIES Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include)

install(TARGETS neural-fortran)

# Install the module files
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/ DESTINATION include)

# Also install the cmake/Findneural-fortran.cmake file
install(FILES cmake/Findneural-fortran.cmake DESTINATION include/cmake/neural-fortran)

# Remove leading or trailing whitespace
string(REGEX REPLACE "^ | $" "" LIBS "${LIBS}")

if(${PROJECT_NAME}_BUILD_TESTING)
message(STATUS "Building tests")
add_subdirectory(test)
endif()

if(${PROJECT_NAME}_BUILD_EXAMPLES)
message(STATUS "Building examples")
add_subdirectory(example)
endif()
22 changes: 18 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,17 +183,31 @@ find or fetch an installation of this project while configuring your project. Th
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.
First, either copy `Findneural-fortran.cmake` to, say, your project's `cmake` directory
and then include it in your `CMakeLists.txt` file:

```cmake
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
```
or use the `CMAKE_MODULE_PATH` variable to point to the directory where it is installed.

Next you need to set `neural-fortran_ROOT_DIR` to the directory where neural-fortran is installed
such that `neural-fortran_ROOT_DIR/lib/libneural-fortran.a` exists.

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)
if(NOT TARGET neural-fortran::neural-fortran)
find_package(neural-fortran REQUIRED)
endif()
```

and then to use the target in your project:

```cmake
target_link_libraries(your_target PRIVATE neural-fortran::neural-fortran)
```

## Examples

The easiest way to get a sense of how to use neural-fortran is to look at
Expand Down
208 changes: 30 additions & 178 deletions cmake/Findneural-fortran.cmake
Original file line number Diff line number Diff line change
@@ -1,179 +1,31 @@
# 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")
# Find the native neural-fortran includes and library
#
# neural-fortran_INCLUDE_DIRS - where to find nf.mod, etc.
# neural-fortran_LIBRARIES - List of libraries when using neural-fortran.
# neural-fortran_FOUND - True if neural-fortran found.
#
# To use neural-fortran_ROOT_DIR to specify the prefix directory of neural-fortran


find_path(neural-fortran_INCLUDE_DIRS
NAMES nf.mod
HINTS ${neural-fortran_ROOT_DIR}/include ENV neural-fortran_INCLUDE_DIR)

find_library(neural-fortran_LIBRARIES
NAMES neural-fortran
HINTS ${neural-fortran_ROOT_DIR}/lib ENV neural-fortran_LIB_DIR)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(neural-fortran DEFAULT_MSG neural-fortran_LIBRARIES neural-fortran_INCLUDE_DIRS)

mark_as_advanced(
neural-fortran_LIBRARIES
neural-fortran_INCLUDE_DIRS)

if(neural-fortran_FOUND AND NOT (TARGET neural-fortran::neural-fortran))
add_library (neural-fortran::neural-fortran STATIC IMPORTED)
set_target_properties(neural-fortran::neural-fortran
PROPERTIES
IMPORTED_LOCATION ${neural-fortran_LIBRARIES}
INTERFACE_INCLUDE_DIRECTORIES ${neural-fortran_INCLUDE_DIRS})
endif()
unset(_lib)
unset(_pkg)
unset(_url)

0 comments on commit d516437

Please sign in to comment.