diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 10541ab4..107bbbe6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -173,17 +173,21 @@ jobs: --julia-depot ~/.julia \ --force - - name: Build libtrixi using PackageCompiler + - name: Configure (test_type == 'package-compiler') if: ${{ matrix.test_type == 'package-compiler' }} run: | - cd LibTrixi.jl/lib - make + mkdir build + cd build + cmake .. -DCMAKE_INSTALL_PREFIX=../install \ + -DCMAKE_BUILD_TYPE=Debug \ + -DUSE_PACKAGE_COMPILER=ON \ + -DJULIA_PROJECT_PATH=$PWD/../libtrixi-julia - - name: Build example + - name: Build (test_type == 'package-compiler') if: ${{ matrix.test_type == 'package-compiler' }} run: | - cd examples - make -f MakefileCompiled LIBTRIXI_PREFIX=$PWD/../LibTrixi.jl/lib/build + cd build + make -j2 - name: Test external CMake project if: ${{ matrix.test_type == 'regular' }} @@ -230,10 +234,10 @@ jobs: - name: Run examples if: ${{ matrix.test_type == 'package-compiler' }} run: | - cd examples + cd build/examples mpirun -n 2 simple_trixi_controller_c \ - ../libtrixi-julia \ - ../LibTrixi.jl/examples/libelixir_p4est2d_dgsem_euler_sedov.jl + ../../libtrixi-julia \ + ../../LibTrixi.jl/examples/libelixir_p4est2d_dgsem_euler_sedov.jl env: LIBTRIXI_DEBUG: all diff --git a/CMakeLists.txt b/CMakeLists.txt index ea99197c..c4d13125 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,78 +56,135 @@ if( ENABLE_TESTING ) find_package( GTest REQUIRED ) set ( TEST_DRIVE_FIND_METHOD fetch ) - # option TEST_DRIVE_BUILD_TESTING is hard-coded to ON + # Option TEST_DRIVE_BUILD_TESTING is hard-coded to ON, could be spared find_package( test-drive REQUIRED ) endif() +# Optionally use PackageCompiler.jl to build standalone libtrixi.so +option( USE_PACKAGE_COMPILER "Build standalone libtrixi.so using PackageCompiler.jl" ) +# Fortran mod file location +set(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}) -# Library target -add_library ( ${PROJECT_NAME} SHARED - src/api.c - src/api.f90 - src/auxiliary.h - src/auxiliary.c - src/trixi.h -) +if( USE_PACKAGE_COMPILER ) + if ( NOT DEFINED JULIA_PROJECT_PATH ) + message( FATAL_ERROR "JULIA_PROJECT_PATH needs to be set for PackageCompiler.jl.") + endif() + if ( ENABLE_TESTING ) + message( NOTICE "Testing is not supported when PackageCompiler is used.") + endif() -# Include directories, private -target_include_directories ( ${PROJECT_NAME} PRIVATE src ) + # Define PackageCompiler.jl output file + set( PC_LIBTRIXI_SO ${CMAKE_BINARY_DIR}/prefix-pc/lib/libtrixi.so ) + + # Define PackageCompiler.jl initialization source file + set( PC_INIT_SOURCE ${CMAKE_SOURCE_DIR}/LibTrixi.jl/lib/init.c ) + set( PC_INIT_BUILD ${CMAKE_BINARY_DIR}/build-pc/init.c ) + + # Copy initialization source to build directory + add_custom_command( OUTPUT ${PC_INIT_BUILD} + COMMENT "Copying `init.c` to build folder..." + COMMAND ${CMAKE_COMMAND} -E copy ${PC_INIT_SOURCE} ${PC_INIT_BUILD} + DEPENDS ${PC_INIT_SOURCE} ) + + # Add a library target (libtrixi), only for Fortran module + add_library( ${PROJECT_NAME} OBJECT + src/api.f90 + ) + + # Custom command to run PackageCompiler.jl to produce libtrixi.so + add_custom_command( OUTPUT ${PC_LIBTRIXI_SO} + COMMENT "Building ${PROJECT_NAME} with PackageCompiler.jl..." + COMMAND ${JULIA_EXECUTABLE} + --project=${CMAKE_SOURCE_DIR}/LibTrixi.jl/lib + ${CMAKE_SOURCE_DIR}/LibTrixi.jl/lib/build.jl + ${JULIA_PROJECT_PATH} + ${CMAKE_BINARY_DIR}/prefix-pc + DEPENDS ${PC_INIT_BUILD} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/build-pc ) + + # Custom target for PackageCompiler.jl's libtrixi.so + add_custom_target( PC_LIBTRIXI DEPENDS ${PC_LIBTRIXI_SO} ) + + # Dependency of main library target on PackageCompiler.jl target + add_dependencies( ${PROJECT_NAME} PC_LIBTRIXI ) + + # Add linking to PackageCompiler.jl's libtrixi.so + target_link_libraries( ${PROJECT_NAME} INTERFACE ${PC_LIBTRIXI_SO} ) + + # Install configuration + install( DIRECTORY "${CMAKE_BINARY_DIR}/prefix-pc/lib/" TYPE LIB ) + install( DIRECTORY "${CMAKE_BINARY_DIR}/prefix-pc/share/julia" + DESTINATION share ) +else() + # Library target + add_library ( ${PROJECT_NAME} SHARED + src/api.c + src/api.f90 + src/auxiliary.h + src/auxiliary.c + src/trixi.h + ) -# Version info -set_target_properties ( ${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION} ) + # Include directories, private + target_include_directories ( ${PROJECT_NAME} PRIVATE src ) -# Version info for the shared object -set_target_properties ( ${PROJECT_NAME} PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR} ) + # Version info + set_target_properties ( ${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION} ) -# Include directories, public for actual users -set_target_properties ( ${PROJECT_NAME} PROPERTIES PUBLIC_HEADER src/trixi.h ) + # Version info for the shared object + set_target_properties ( ${PROJECT_NAME} PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR} ) -# Fortran mod file location -set(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}) + # Include directories + target_include_directories( ${PROJECT_NAME} PRIVATE src ${JULIA_INCLUDE_DIRS} ) + if ( T8CODE_FOUND ) + target_include_directories( ${PROJECT_NAME} PRIVATE ${T8CODE_INCLUDE_DIR} ) + endif() -# Include directories -target_include_directories( ${PROJECT_NAME} PRIVATE src ${JULIA_INCLUDE_DIRS} ) -if ( T8CODE_FOUND ) - target_include_directories( ${PROJECT_NAME} PRIVATE ${T8CODE_INCLUDE_DIR} ) -endif() + # Libraries to link + target_link_libraries( ${PROJECT_NAME} PRIVATE ${JULIA_LIBRARY} ) -# Libraries to link -target_link_libraries( ${PROJECT_NAME} PRIVATE ${JULIA_LIBRARY} ) + # Set appropriate compile flags + target_compile_options( ${PROJECT_NAME} PUBLIC "-fPIC" ) + target_compile_options( ${PROJECT_NAME} PRIVATE -Wall -Wextra -Werror) + # Require C11 standard with GNU extensions for C files + target_compile_options( ${PROJECT_NAME} PRIVATE $<$:-std=gnu11>) + # Require Fortran 2018 standard for Fortran files + target_compile_options( ${PROJECT_NAME} PRIVATE $<$:-std=f2018>) -# Set appropriate compile flags -target_compile_options( ${PROJECT_NAME} PUBLIC "-fPIC" ) -target_compile_options( ${PROJECT_NAME} PRIVATE -Wall -Wextra -Werror) -# Require C11 standard with GNU extensions for C files -target_compile_options( ${PROJECT_NAME} PRIVATE $<$:-std=gnu11>) -# Require Fortran 2018 standard for Fortran files -target_compile_options( ${PROJECT_NAME} PRIVATE $<$:-std=f2018>) + # Add auxiliary *object* library to support fast thread-local storage (TLS) + add_library ( ${PROJECT_NAME}_tls OBJECT + src/tls.c + ) + target_include_directories( ${PROJECT_NAME}_tls PRIVATE ${JULIA_INCLUDE_DIRS} ) -# Add auxiliary *object* library to support fast thread-local storage (TLS) -add_library ( ${PROJECT_NAME}_tls OBJECT - src/tls.c -) -target_include_directories( ${PROJECT_NAME}_tls PRIVATE ${JULIA_INCLUDE_DIRS} ) + # Add test on demand + if( ENABLE_TESTING ) + enable_testing() + add_subdirectory( test/c ) + add_subdirectory( test/fortran ) + endif() -# Add examples -add_subdirectory( examples ) -# Add test on demand -if( ENABLE_TESTING ) - enable_testing() - add_subdirectory( test/c ) - add_subdirectory( test/fortran ) + # Install configuration + install( FILES $ TYPE LIB RENAME lib${PROJECT_NAME}_tls.o ) + install( FILES "${CMAKE_BINARY_DIR}/LIBTRIXI_VERSION" DESTINATION share/julia ) endif() -# Install configuration + +# Public header for libtrixi +set_target_properties ( ${PROJECT_NAME} PROPERTIES PUBLIC_HEADER src/trixi.h ) + +# Common install configuration install( TARGETS ${PROJECT_NAME} ) +install( DIRECTORY LibTrixi.jl DESTINATION share/libtrixi PATTERN "lib" EXCLUDE ) install( FILES ${CMAKE_Fortran_MODULE_DIRECTORY}/libtrixi.mod TYPE INCLUDE) -install( FILES $ TYPE LIB RENAME lib${PROJECT_NAME}_tls.o ) -install( DIRECTORY LibTrixi.jl DESTINATION share/libtrixi ) -install( FILES "${CMAKE_BINARY_DIR}/LIBTRIXI_VERSION" DESTINATION share/julia ) install( PROGRAMS utils/libtrixi-init-julia TYPE BIN ) + +# Add examples +add_subdirectory( examples ) diff --git a/README.md b/README.md index c37ffe61..3dffc16a 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ For building, `cmake` and its typical workflow is used. 2. Call cmake ```bash - cmake -DCMAKE_BUILD_TYPE=(debug|release) -DCMAKE_INSTALL_PREFIX= .. + cmake -DCMAKE_BUILD_TYPE=(Debug|Release) -DCMAKE_INSTALL_PREFIX= .. ``` `cmake` should find `MPI` and `Julia` automatically. If not, the directories @@ -276,23 +276,33 @@ library with a C interface. This is possible with the use of the Julia package [PackageCompiler.jl](https://github.com/JuliaLang/PackageCompiler.jl). To try this out, perform the following steps: -1. Initialize the project directory `libtrixi-julia` using `libtrixi-init-julia` as - described above. -2. Go to the `LibTrixi.jl/lib` directory in the repository root, - make sure that `PROJECT_DIR` (defined in `Makefile`) points to your `libtrixi-julia` directory, - and call `make`: - ```shell - cd LibTrixi.jl/lib - make - ``` -3. Go to the `examples` folder in the repository root and compile - `simple_trixi_controller_c`: - ```shell - cd examples - make -f MakefileCompiled LIBTRIXI_PREFIX=$PWD/../LibTrixi.jl/lib/build - ``` - This will create a `simple_trixi_controller_c` file. -4. From inside the `examples` folder you should be able to run the example (in parallel) +1. Initialize the project directory `libtrixi-julia` using `libtrixi-init-julia` as + described above. +2. Build + + *using make* + - Go to the `LibTrixi.jl/lib` directory in the repository root, + make sure that `PROJECT_DIR` (defined in `Makefile`) points to your `libtrixi-julia` directory, + and call `make`: + ```shell + cd LibTrixi.jl/lib + make + ``` + - Go to the `examples` folder in the repository root and compile + `simple_trixi_controller_c`: + ```shell + cd examples + make -f MakefileCompiled LIBTRIXI_PREFIX=$PWD/../LibTrixi.jl/lib/build + ``` + This will create a `simple_trixi_controller_c` file. + + *using cmake* + - Add + ``` + -DUSE_PACKAGE_COMPILER=ON -DJULIA_PROJECT_PATH= + ``` + to your cmake call (see above) +3. From inside the `examples` folder you should be able to run the example (in parallel) with the following command: ```shell mpirun -n 2 simple_trixi_controller_c \ diff --git a/docs/src/index.md b/docs/src/index.md index 9d75dcff..a7fa1564 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -49,7 +49,7 @@ For building, `cmake` and its typical workflow is used. 2. Call cmake ```bash - cmake -DCMAKE_BUILD_TYPE=(debug|release) -DCMAKE_INSTALL_PREFIX= .. + cmake -DCMAKE_BUILD_TYPE=(Debug|Release) -DCMAKE_INSTALL_PREFIX= .. ``` `cmake` should find `MPI` and `Julia` automatically. If not, the directories @@ -278,21 +278,31 @@ library with a C interface. This is possible with the use of the Julia package To try this out, perform the following steps: 1. Initialize the project directory `libtrixi-julia` using `libtrixi-init-julia` as described above. -2. Go to the `LibTrixi.jl/lib` directory in the repository root, - make sure that `PROJECT_DIR` (defined in `Makefile`) point to your `libtrixi-julia` directory, - and call `make`: - ```shell - cd LibTrixi.jl/lib - make - ``` -3. Go to the `examples` folder in the repository root and compile - `simple_trixi_controller_c`: - ```shell - cd examples - make -f MakefileCompiled LIBTRIXI_PREFIX=$PWD/../LibTrixi.jl/lib/build - ``` - This will create a `simple_trixi_controller_c` file. -4. From inside the `examples` folder you should be able to run the example (in parallel) +2. Build + + *using make* + - Go to the `LibTrixi.jl/lib` directory in the repository root, + make sure that `PROJECT_DIR` (defined in `Makefile`) points to your `libtrixi-julia` directory, + and call `make`: + ```shell + cd LibTrixi.jl/lib + make + ``` + - Go to the `examples` folder in the repository root and compile + `simple_trixi_controller_c`: + ```shell + cd examples + make -f MakefileCompiled LIBTRIXI_PREFIX=$PWD/../LibTrixi.jl/lib/build + ``` + This will create a `simple_trixi_controller_c` file. + + *using cmake* + - Add + ``` + -DUSE_PACKAGE_COMPILER=ON -DJULIA_PROJECT_PATH= + ``` + to your cmake call (see above) +3. From inside the `examples` folder you should be able to run the example (in parallel) with the following command: ```shell mpirun -n 2 simple_trixi_controller_c \ diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index b1c8ff39..7b6c899a 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -31,8 +31,11 @@ foreach ( EXAMPLE ${EXAMPLES} ) # set libraries to link target_link_libraries( ${TARGET_NAME} - PRIVATE MPI::MPI_${EXAMPLE_LANG} ${PROJECT_NAME} ${PROJECT_NAME}_tls + PRIVATE MPI::MPI_${EXAMPLE_LANG} ${PROJECT_NAME} ) + if ( NOT USE_PACKAGE_COMPILER ) + target_link_libraries( ${TARGET_NAME} PRIVATE ${PROJECT_NAME}_tls ) + endif() if ( T8CODE_FOUND ) target_link_libraries( ${TARGET_NAME} PRIVATE ${T8CODE_LIBRARIES} ) endif() @@ -52,6 +55,9 @@ foreach ( EXAMPLE ${EXAMPLES} ) PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib" ) + # position independent code + target_compile_options( ${TARGET_NAME} PRIVATE "-fPIC" ) + # enable warnings target_compile_options( ${TARGET_NAME} PRIVATE -Wall -Wextra -Werror )