Skip to content

Improve CMake #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/docker-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ on:
branches:
- main
pull_request:
workflow_dispatch:
inputs:
use_cache:
description: 'Use cache for this run'
required: true
default: 'true'

jobs:
build:
Expand All @@ -30,6 +36,7 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}

- name: Cache build directory
if: github.event_name != 'workflow_dispatch' || github.event.inputs.use_cache == 'true'
uses: actions/cache@v3
with:
path: build
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.10)
project(RawHash2)
project(RawHash2Root)

add_subdirectory(src)
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ COPY . /rawhash2

RUN mkdir -p build && cd build \
&& cmake .. \
&& make -j 3
&& make -j 2

ENTRYPOINT ["./build/bin/rawhash2"]

Expand Down
22 changes: 21 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ cd rawhash2 && git submodule update --init --recursive
# if not doing a fresh clone, make sure that the submodules don't have anything built from previous makefile-based
# setup , i.e. delete extern directory, then initialize submodules as above
(mkdir -p build && cd build && cmake .. && make -j)
build/bin/rawhash2
build/bin/rawhash2 -h
```

Troubleshooting:
Expand All @@ -54,6 +54,26 @@ Troubleshooting:

If the compilation is successful, the default path to the binary will be `build/bin/rawhash2`.

* Installation

You can install RawHash2 into the CMake-provided platform-specific destination (e.g. `/usr/local/` on UNIX) with `make install`:

```bash
make install
rawhash2 -h
```

Installation directory can be overridden by providing `-DCMAKE_INSTALL_PREFIX=...` argument to the `cmake ..` command, e.g.

```bash
cmake -DCMAKE_INSTALL_PREFIX=./install ..
make -j
make install
./install/bin/rawhash2 -h
```

Note that `CMAKE_INSTALL_PREFIX` is a cached variable in CMake.

## Compiling with HDF5, SLOW5, and POD5

We are aware that some of the pre-compiled libraries (e.g., POD5) may not work in your system and you may need to compile these libraries from scratch. Additionally, it may be possible that you may not want to compile any of the HDF5, SLOW5, or POD5 libraries if you are not going to use them. RawHash2 provides several CMake options to enable custom compilation of these libraries.
Expand Down
16 changes: 12 additions & 4 deletions cmake/SetupHDF5.cmake
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
include(${CMAKE_CURRENT_LIST_DIR}/Util.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/Utils.cmake)

function(setup_hdf5 TARGET_NAME)
function(add_hdf5_to_target TARGET_NAME)
if(NOHDF5)
target_compile_definitions(${TARGET_NAME} PRIVATE NHDF5RH=1)
else()
if(HDF5_COMPILE)
add_dependencies(${TARGET_NAME} hdf5_build)
endif()
target_link_libraries(${TARGET_NAME} PRIVATE hdf5)
endif()
endfunction()

function(setup_hdf5)
if(NOT NOHDF5)
# print HDF5_DIR
message(STATUS "EXTERNAL_PROJECTS_BUILD_DIR: ${EXTERNAL_PROJECTS_BUILD_DIR}")
message(STATUS "HDF5_DIR: ${HDF5_DIR}")
Expand All @@ -21,12 +30,11 @@ function(setup_hdf5 TARGET_NAME)
# INSTALL_DIR and DCMAKE_INSTALL_PREFIX are ignored by hdf5
INSTALL_COMMAND make install prefix=${HDF5_DIR}
)
add_dependencies(${TARGET_NAME} hdf5_build)
else()
if(NOT HDF5_DIR)
message(FATAL_ERROR "HDF5_COMPILE is OFF, but no dir provided")
endif()
endif()
link_imported_library(${TARGET_NAME} hdf5 ${HDF5_DIR})
define_imported_library(hdf5 ${HDF5_DIR})
endif()
endfunction()
39 changes: 30 additions & 9 deletions cmake/SetupPOD5.cmake
Original file line number Diff line number Diff line change
@@ -1,22 +1,44 @@
include(${CMAKE_CURRENT_LIST_DIR}/Util.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/Utils.cmake)

function(setup_zstd TARGET_NAME)
set(ZSTD_DIR ${EXTERNAL_PROJECTS_BUILD_DIR}/zstd)
function(add_zstd_to_target TARGET_NAME)
set(ZSTD_DIR ${EXTERNAL_PROJECTS_BUILD_DIR}/zstd)
add_dependencies(${TARGET_NAME} zstd_build)
target_link_libraries(${TARGET_NAME} PRIVATE zstd)
endfunction()

function(setup_zstd)
set(ZSTD_DIR ${EXTERNAL_PROJECTS_BUILD_DIR}/zstd)
ExternalProject_Add(
zstd_build
SOURCE_DIR ${CMAKE_SOURCE_DIR}/extern/zstd/build/cmake
BINARY_DIR ${ZSTD_DIR}/build
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${ZSTD_DIR}
)
add_dependencies(${TARGET_NAME} zstd_build)
link_imported_library(${TARGET_NAME} zstd ${ZSTD_DIR})
define_imported_library(zstd ${ZSTD_DIR})
endfunction()

function(setup_pod5 TARGET_NAME)
function(add_pod5_to_target TARGET_NAME)
if(NOPOD5)
target_compile_definitions(${TARGET_NAME} PRIVATE NPOD5RH=1)
else()
setup_zstd(${TARGET_NAME})
add_zstd_to_target(${TAARGET_NAME})

set(POD5_VERSION "0.2.2")
set(POD5_URLDIR "pod5-${POD5_VERSION}-${CMAKE_SYSTEM_NAME}")
set(POD5_REPO "https://github.com/nanoporetech/pod5-file-format")

resolve_pod5_url()

if(POD5_DOWNLOAD)
add_dependencies(${TARGET_NAME} pod5_download)
endif()
target_link_libraries(${TARGET_NAME} PRIVATE ${POD5_LIBRARIES} zstd)
endif()
endfunction()

function(setup_pod5)
if(NOT NOPOD5)
setup_zstd()

set(POD5_VERSION "0.2.2")
set(POD5_URLDIR "pod5-${POD5_VERSION}-${CMAKE_SYSTEM_NAME}")
Expand Down Expand Up @@ -45,7 +67,6 @@ function(setup_pod5 TARGET_NAME)
endif()
endif()
include_directories(${POD5_DIR}/include)
target_link_libraries(${TARGET_NAME} PRIVATE ${POD5_LIBRARIES} zstd)
endif()
endfunction()

Expand Down Expand Up @@ -79,7 +100,7 @@ endfunction()


# not working because of improper design, PARENT_SCOPE should not be used, rather define targets properly
# include(${CMAKE_CURRENT_LIST_DIR}/Util.cmake)
# include(${CMAKE_CURRENT_LIST_DIR}/Utils.cmake)

# set(ZSTD_DIR ${EXTERNAL_PROJECTS_BUILD_DIR}/zstd)

Expand Down
17 changes: 11 additions & 6 deletions cmake/SetupRUClient.cmake
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
include(${CMAKE_CURRENT_LIST_DIR}/Util.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/Utils.cmake)

function(setup_ruclient TARGET_NAME)
function(add_ruclient_to_target TARGET_NAME)
if(RUCLIENT_ENABLED)
set_target_properties(${TARGET_NAME} PROPERTIES CXX_STANDARD 20)
target_compile_definitions(${TARGET_NAME} PRIVATE RUCLIENT_ENABLED)
target_sources(${TARGET_NAME} PRIVATE rawhash_ruclient.cpp)
add_dependencies(${TARGET_NAME} ruclient_build)
endif()
endfunction()

function(setup_ruclient)
if(RUCLIENT_ENABLED)
set_target_properties(${TARGET_NAME} PROPERTIES CXX_STANDARD 20)
target_compile_definitions(${TARGET_NAME} PRIVATE RUCLIENT_ENABLED)
target_sources(${TARGET_NAME} PRIVATE rawhash_ruclient.cpp)
if(NOT RUCLIENT_DIR)
override_cached(RUCLIENT_DIR ${EXTERNAL_PROJECTS_BUILD_DIR}/ruclient)
endif()
Expand All @@ -15,7 +21,6 @@ function(setup_ruclient TARGET_NAME)
CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX=${RUCLIENT_DIR}
)
add_dependencies(${TARGET_NAME} ruclient_build)
include_directories(${RUCLIENT_DIR}/include)
message(STATUS "ruclient enabled")
else()
Expand Down
18 changes: 18 additions & 0 deletions cmake/SetupRawHashLikeTarget.cmake
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
include(${CMAKE_CURRENT_LIST_DIR}/SetupRUClient.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/SetupPOD5.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/SetupHDF5.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/SetupSLOW5.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/SetupTFLite.cmake)

setup_pod5()
setup_ruclient()
setup_hdf5()
setup_slow5()
setup_tflite()

function(setup_rawhashlike_target TARGET_NAME)
# if(PYBINDING)
# message(FATAL_ERROR "Building with Python binding support is not implemented")
Expand Down Expand Up @@ -77,4 +89,10 @@ function(setup_rawhashlike_target TARGET_NAME)
PROFILERH=1
)
endif()

add_pod5_to_target(${TARGET_NAME})
add_hdf5_to_target(${TARGET_NAME})
add_slow5_to_target(${TARGET_NAME})
add_tflite_to_target(${TARGET_NAME})
add_ruclient_to_target(${TARGET_NAME})
endfunction()
16 changes: 12 additions & 4 deletions cmake/SetupSLOW5.cmake
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
include(${CMAKE_CURRENT_LIST_DIR}/Util.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/Utils.cmake)

function(setup_slow5 TARGET_NAME)
function(add_slow5_to_target TARGET_NAME)
if(NOSLOW5)
target_compile_definitions(${TARGET_NAME} PRIVATE NSLOW5RH=1)
else()
if(SLOW5_COMPILE)
add_dependencies(${TARGET_NAME} slow5_build)
endif()
target_link_libraries(${TARGET_NAME} PRIVATE slow5)
endif()
endfunction()

function(setup_slow5)
if(NOT NOSLOW5)
set(SLOW5_SOURCE_DIR ${CMAKE_SOURCE_DIR}/extern/slow5lib)
if(SLOW5_COMPILE)
if(NOT SLOW5_DIR)
Expand All @@ -19,13 +28,12 @@ function(setup_slow5 TARGET_NAME)
&& ${CMAKE_COMMAND} -E rename ${SLOW5_DIR}/libslow5.so ${SLOW5_DIR}/lib/libslow5.so
)
message(STATUS "Current dir: ${CMAKE_CURRENT_BINARY_DIR}")
add_dependencies(${TARGET_NAME} slow5_build)
else()
if(NOT SLOW5_DIR)
message(FATAL_ERROR "SLOW5_COMPILE is OFF, but no dir provided")
endif()
endif()
message(STATUS "Using slow5 from ${SLOW5_DIR}")
link_imported_library(${TARGET_NAME} slow5 ${SLOW5_DIR})
define_imported_library(slow5 ${SLOW5_DIR})
endif()
endfunction()
9 changes: 6 additions & 3 deletions cmake/SetupTFLite.cmake
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
include(${CMAKE_CURRENT_LIST_DIR}/Util.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/Utils.cmake)

function(setup_tflite TARGET_NAME)
function(add_tflite_to_target TARGET_NAME)
target_link_libraries(${TARGET_NAME} PRIVATE tensorflow-lite)
endfunction()

function(setup_tflite)
set(TF_SOURCE_DIR ${CMAKE_SOURCE_DIR}/extern/tensorflow)
add_subdirectory(${TF_SOURCE_DIR}/tensorflow/lite ${EXTERNAL_PROJECTS_BUILD_DIR}/tflite EXCLUDE_FROM_ALL)
include_directories(${TF_SOURCE_DIR})
target_link_libraries(${TARGET_NAME} PRIVATE tensorflow-lite)
endfunction()
16 changes: 11 additions & 5 deletions cmake/Util.cmake → cmake/Utils.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,22 @@ function(override_cached name value)
set(${name} ${value} CACHE ${type} ${doc_string} FORCE)
endfunction()

function(link_imported_library TARGET_NAME LIB_NAME LIB_DIR)

function(define_imported_library LIB_NAME LIB_DIR)
add_library(${LIB_NAME} SHARED IMPORTED)
file(MAKE_DIRECTORY ${LIB_DIR}/include)
set_target_properties(${LIB_NAME} PROPERTIES
IMPORTED_LOCATION ${LIB_DIR}/lib/lib${LIB_NAME}.so
INTERFACE_INCLUDE_DIRECTORIES ${LIB_DIR}/include
)
target_link_libraries(${TARGET_NAME} PRIVATE ${LIB_NAME})
INTERFACE_INCLUDE_DIRECTORIES ${LIB_DIR}/include)
file(MAKE_DIRECTORY ${LIB_DIR}/include)
# Can't install(TARGETS ...) for external projects
# Also some .so are symlinks, so install all
install(DIRECTORY ${LIB_DIR}/lib/ DESTINATION lib
FILES_MATCHING PATTERN "*.so*")
install(DIRECTORY ${LIB_DIR}/include/
DESTINATION include/${PROJECT_NAME})
endfunction()


function(check_directory_exists_and_non_empty DIR)
if(NOT EXISTS ${DIR})
message(FATAL_ERROR "Directory ${DIR} does not exist.")
Expand Down
68 changes: 17 additions & 51 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.10)
project(RawHash2Src)
project(RawHash2)

# option(USE_CCACHE "Use ccache to speed up rebuilds" ON)
# option(USE_MOLD "Use mold linker for faster linking" ON)
Expand Down Expand Up @@ -34,62 +34,28 @@ set(EXTERNAL_PROJECTS_BUILD_DIR ${CMAKE_BINARY_DIR}/extern) # default build dire
file(MAKE_DIRECTORY ${EXTERNAL_PROJECTS_BUILD_DIR})
message(STATUS "External projects build directory: ${EXTERNAL_PROJECTS_BUILD_DIR}")

include(../cmake/SetupCCacheMold.cmake)
include(../cmake/SetupRawHashLikeTarget.cmake)
include(../cmake/SetupRUClient.cmake)
include(../cmake/SetupPOD5.cmake)
include(../cmake/SetupHDF5.cmake)
include(../cmake/SetupSLOW5.cmake)
include(../cmake/SetupTFLite.cmake)
include(${CMAKE_SOURCE_DIR}/cmake/SetupCCacheMold.cmake)
include(${CMAKE_SOURCE_DIR}/cmake/SetupRawHashLikeTarget.cmake)

set(CMAKE_VERBOSE_MAKEFILE TRUE CACHE BOOL "verbose makefile" FORCE) # print compilation commands

enable_ccache()
set_alternate_linker(mold)

# todo: currently can only compile rawhash2 or the below, not both
# this happens because functions like setup_hdf5 define the hdf5 target and the relationship to the target name
# rather than doing it separately
set(build_cli ON)
add_executable(rawhash2_builtin main.cpp)
setup_rawhashlike_target(rawhash2_builtin)

if (build_cli)
message(STATUS "Building CLI")

set(TARGET_NAME rawhash2)
add_executable(${TARGET_NAME} main.cpp)
setup_rawhashlike_target(${TARGET_NAME})
setup_pod5(${TARGET_NAME})
setup_ruclient(${TARGET_NAME})
setup_hdf5(${TARGET_NAME})
setup_slow5(${TARGET_NAME})
setup_tflite(${TARGET_NAME})
add_library(rawhash2_lib SHARED rawhash_wrapper.cpp rawhash_wrapper.hpp)
setup_rawhashlike_target(rawhash2_lib)

else()
message(STATUS "Building shared library")
file(GLOB_RECURSE HEADER_FILES ${CMAKE_SOURCE_DIR}/src/*.h ${CMAKE_SOURCE_DIR}/src/*.hpp)
set_property(TARGET rawhash2_lib PROPERTY PUBLIC_HEADER ${HEADER_FILES})
set_target_properties(rawhash2_lib PROPERTIES INSTALL_RPATH $ORIGIN OUTPUT_NAME rawhash2)
install(TARGETS rawhash2_lib
LIBRARY DESTINATION lib
PUBLIC_HEADER DESTINATION include/${PROJECT_NAME})

# set(TARGET_NAME rawhash2_wrapper_example)
# add_executable(${TARGET_NAME} wrapper_example.cpp rawhash_wrapper.cpp rawhash_wrapper.hpp)
set(TARGET_NAME rawhash2_wrapper)
add_library(${TARGET_NAME} SHARED rawhash_wrapper.cpp rawhash_wrapper.hpp)
setup_rawhashlike_target(${TARGET_NAME})
setup_pod5(${TARGET_NAME})
setup_ruclient(${TARGET_NAME})
setup_hdf5(${TARGET_NAME})
setup_slow5(${TARGET_NAME})
setup_tflite(${TARGET_NAME})

set(TARGET_NAME rawhash2_usinglib)
add_executable(${TARGET_NAME} wrapper_example.cpp)
target_link_libraries(${TARGET_NAME} PRIVATE rawhash2_wrapper)
# setup_rawhashlike_target(${TARGET_NAME})
# # setup_pod5(${TARGET_NAME})
# target_compile_definitions(${TARGET_NAME} PRIVATE NPOD5RH=1) # todo: workaround
# setup_ruclient(${TARGET_NAME})
# setup_hdf5(${TARGET_NAME})
# setup_slow5(${TARGET_NAME})
# setup_tflite(${TARGET_NAME})
endif()


# setup_pod5()
# add_pod5_to_target(${TARGET_NAME})
add_executable(rawhash2 wrapper_example.cpp)
target_link_libraries(rawhash2 PRIVATE rawhash2_lib)
set_target_properties(rawhash2 PROPERTIES INSTALL_RPATH $ORIGIN/../lib)
install(TARGETS rawhash2 RUNTIME DESTINATION bin)
Copy link
Collaborator Author

@adamant-pwn adamant-pwn Jul 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently make install would install the shared library and also an executable that links to it. Should we install an executable that doesn't link to the rawhash2 shared library as well? Also generally what's the reason to build both rawhash2_builtin (former rawhash2) and rawhash2 (former rawhash2_usinglib) targets?

Copy link
Collaborator

@maximilianmordig maximilianmordig Aug 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you can build a shared and static library. The python wrapper needs a shared library, if I remember well.
The important thing is that both the rawhash python wrapper and rawhash cli can be built at the same time, unlike previously.
I used rawhash_lib, so that it can be included as a library in both the cli and the python wrapper, but this is not necessary if the above goal is met.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we should be able to build both currently. What I'm really asking is: During the install, should we install both the "standalone" client and the client that depends on the static library, or only one of them? If only one, which? Would it be okay to only install the client that depends on RawHash shared library?

Loading