0% found this document useful (0 votes)
10 views

hpc_cmake

Uploaded by

Rajul
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
10 views

hpc_cmake

Uploaded by

Rajul
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 76

Building projects with CMake

Victor Eijkhout

Fall 2023

1 Eijkhout – CMake tutorial – Fall 2023


Justification

CMake is a portable build system that is becoming a de facto standard for


C++ package management.
Also usable with C and Fortran.

2 Eijkhout – CMake tutorial – Fall 2023


Table of contents

1 Help! This software uses CMake!


Using a cmake-based library
Using CMake packages through pkgconfig

2 Help! I want to write CMake myself!


Make your own CMake configuration

3 Help! I want people to use my CMake package!


Making your package discoverable through pkgconfig

4 Example libraries
Parallelism

5 TBB
Data packages
More libraries

3 Eijkhout – CMake tutorial – Fall 2023


Help! This software uses
CMake!

4 Eijkhout – CMake tutorial – Fall 2023


Using a cmake-based library

5 Eijkhout – CMake tutorial – Fall 2023


What are we talking here?

You have downloaded a library


It contains a file CMakeLists.txt
⇒ you need to install it with CMake.
. . . and then figure out how to use it in your code.

6 Eijkhout – CMake tutorial – Fall 2023


Building with CMake

Use CMake for the configure stage, then make:


cmake -D CMAKE_INSTALL_PREFIX=/home/yourname/packages \
/home/your/software/package ## source location
make
make install

or
do everything with CMake:
cmake ## arguments
cmake --build ## stuff
cmake --install ## stuff

We focus on the first option; the second one is portable to non-Unix


environments.

7 Eijkhout – CMake tutorial – Fall 2023


What does this buy you?

1. The source directory is untouched


2. The build directory contains all temporaries
3. Your install directory (as specified to CMake) now contains executables,
libraries, headers etc.
You can add these to $PATH, compiler options, $LD_LIBRARY_PATH.
But see later . . .

8 Eijkhout – CMake tutorial – Fall 2023


The build/make cycle

CMake creates makefiles;


makefiles ensure minimal required compilation
cmake ## make the makefiles
make ## compile your project
emacs onefile.c ## edit
make ## minimal recompile

Only if you add (include) files do you rerun CMake.

9 Eijkhout – CMake tutorial – Fall 2023


Directory structure: two options

dir dir

src src

build build

install install
In-source build: pretty common
Out-of-source build: cleaner because never touches the source tree
Some people skip the install step, and use everything from the build
directory.

10 Eijkhout – CMake tutorial – Fall 2023


Out-of-source build: preferred

Work from a build directory


Specify prefix and location of CMakeLists.txt

1 ls some_package_1.0.0 # we are outside the source


2 ls some_package_1.0.0/CMakeLists.txt # source contains cmake file
3 mkdir builddir # location for temporaries
4 cd builddir # goto build location
5 cmake -D CMAKE_INSTALL_PREFIX=../installdir \
6 ../some_package_1.0.0 # cmake invocation
7 make # make all tmp data in build loc
8 make install # move only final products

11 Eijkhout – CMake tutorial – Fall 2023


Example: eigen

Download from
https://eigen.tuxfamily.org/index.php
and install.
What compiler is it finding? If you are at TACC, is it the module you have
loaded?

12 Eijkhout – CMake tutorial – Fall 2023


Basic customizations

Compiler settings:
cmake -D CMAKE_CXX_COMPILER=icpx

Alternatively:
export CXX=icpx
cmake .......

Many settings can be done on the commandline:


-D BUILD_SHARED_LIBS=ON

Also check out the ccmake utility.

13 Eijkhout – CMake tutorial – Fall 2023


Tracing and logging

CMake prints some sort of progress messages.


To see commandlines:
cmake -D CMAKE_VERBOSE_MAKEFILE=ON ...
make V=1

CMake leaves behind a log and error file, but these are insufficent:
⇒ use the above verbose mode and capture all output.

14 Eijkhout – CMake tutorial – Fall 2023


Using CMake packages through pkgconfig

15 Eijkhout – CMake tutorial – Fall 2023


What are we talking here?

You have just installed a CMake-based library.


Now you need it in your own code, or in another library.
How easy can we make that?

16 Eijkhout – CMake tutorial – Fall 2023


Problem

You want to install an application/package


. . . which needs 2 or 3 other packages.
gcc -o myprogram myprogram.c \
-I/users/my/package1/include \
-L/users/my/package1/lib \
-I/users/my/package2/include/package \
-L/users/my/package2/lib64

or:
cmake \
-D PACKAGE1_INC=/users/my/package1/include \
-D PACKAGE1_LIB=/users/my/package1/lib \
-D PACKAGE2_INC=/users/my/package2/include/package \
-D PACKAGE2_LIB=/users/my/package2/lib64 \
../newpackage

Can this be made simpler?

17 Eijkhout – CMake tutorial – Fall 2023


Finding packages with ‘pkg config’

Many packages come with a package.pc file


Add that location to PKG_CONFIG_PATH
The package can now be found by other CMake-based packages.

18 Eijkhout – CMake tutorial – Fall 2023


Package config settings

Let’s say you’ve installed a library with CMake.


Somewhere in the installation is a .pc file:
find $TACC_SMTHNG_DIR -name \*.pc
${TACC_SMTHNG_DIR}/share/pkgconfig/smthng3.pc

That location needs to be on the PKG_CONFIG_PATH:


export PKG_CONFIG_PATH=${TACC_SMTHNG_DIR}/share/pkgconfig:${
PKG_CONFIG_PATH}

19 Eijkhout – CMake tutorial – Fall 2023


Example: eigen

Can you find the .pc file in the Eigen installation?

20 Eijkhout – CMake tutorial – Fall 2023


Scenario 1: finding without cmake

Packages with a .pc file can be found through the pkg-config command:
gcc -o myprogram myprogram.c \
$( pkg-config --cflags package1 ) \
$( pkg-config --libs package1 )

In a makefile:
CFLAGS = -g -O2 $$( pkg-config --cflags package1 )

21 Eijkhout – CMake tutorial – Fall 2023


Example: eigen

#include "Eigen/Core"
int main(int argc,char **argv) {
return 0;
}

Can you compile this on the commandline, using pkg-config? Small


problem: ‘eigen’ wants to be called ‘eigen3’.

22 Eijkhout – CMake tutorial – Fall 2023


Scenario 2: finding from CMake

You are installing a CMake-based library


and it needs Eigen, which is also CMake-based
1. you install Eigen with CMake, as above
2. you add the location of eigen.pc to PKG_CONFIG_PATH
3. you run the installation of the higher library:
this works because it can now find Eigen.

23 Eijkhout – CMake tutorial – Fall 2023


Lifting the veil

So how does a CMake install find libraries such as Eigen?


1 cmake_minimum_required( VERSION 3.12 )
2 project( eigentest )
3

4 find_package( PkgConfig REQUIRED )


5 pkg_check_modules( EIGEN REQUIRED eigen3 )
6

7 add_executable( eigentest eigentest.cxx )


8 target_include_directories(
9 eigentest PUBLIC
10 ${EIGEN_INCLUDE_DIRS})

Note 1: header-only so no library, otherwise PACKAGE_LIBRARY_DIRS and


PACKAGE_LIBRARIES defined.
Note 2: you will learn how to write these configurations in the second part.

24 Eijkhout – CMake tutorial – Fall 2023


Summary for now

You can use CMake to install libraries;


You can use these libraries from commandline / makefile;
You can let other CMake-based libraries find them.

25 Eijkhout – CMake tutorial – Fall 2023


Other discovery mechanisms

Some packages come with FindWhatever.cmake or similar files.


Add package root to CMAKE_MODULE_PATH
Pity that there is not just one standard.
These define some macros, but you need to read the docs to see which.
Pity that there is not just one standard.
Some examples follow.

26 Eijkhout – CMake tutorial – Fall 2023


Help! I want to write CMake
myself!

27 Eijkhout – CMake tutorial – Fall 2023


Make your own CMake configuration

28 Eijkhout – CMake tutorial – Fall 2023


What are we talking here?

You have a code that you want to distribute in source form for easy
installation.
You decide to use CMake for portability.
You think that using CMake might make life easier.
⇒ To do: write the CMakeLists.txt file.

29 Eijkhout – CMake tutorial – Fall 2023


The CMakeLists file

cmake_minimum_required( VERSION 3.12 )


project( myproject VERSION 1.0 )

Which cmake version is needed for this file?


(CMake has undergone quite some evolution!)
Give a name to your project.
Maybe pick a language.
C and C++ available by default, or:
enable_language(Fortran)

(list: C, CXX, CSharp, CUDA, OBJC, OBJCXX, Fortran, HIP, ISPC, Swift,
and a couple of variants of ASM)

30 Eijkhout – CMake tutorial – Fall 2023


Target philosophy

Declare a target: something that needs to be built, and specify what is


needed for it
add_executable( myprogram )
target_sources( myprogram PRIVATE program.cxx )

Use of macros:
add_executable( ${PROJECT_NAME} )

Do things with the target, for instance state where it is to be installed:


install( TARGETS myprogram DESTINATION . )

relative to the prefix location.

31 Eijkhout – CMake tutorial – Fall 2023


Example: single source

Build an executable from a single source file:


cmake_minimum_required( VERSION 3.12 )
project( singleprogram VERSION 1.0 )

add_executable( program )
target_sources( program PRIVATE program.cxx )
install( TARGETS program DESTINATION . )

32 Eijkhout – CMake tutorial – Fall 2023


Deprecated usage

add_executable( myprogram myprogram.c myprogram.h )

Prefer ‘target’ design.

33 Eijkhout – CMake tutorial – Fall 2023


Exercise

Write a ‘hello world’ program;


Make a CMake setup to compile and install it;
Test it all.

34 Eijkhout – CMake tutorial – Fall 2023


Exercise: using the Eigen library

This is a short program using Eigen:


#include <iostream>
#include <Eigen/Dense>

int main() {
// Define a 3x3 matrix
Eigen::Matrix3d matrix;
matrix << 1, 2, 3,
4, 5, 6,
7, 8, 9;
std::cout << "Original matrix:\n" << matrix << std::endl;
return 0;
}

Make a CMake setup to compile and install it;


Test it.

35 Eijkhout – CMake tutorial – Fall 2023


Make your own library

First a library that goes into the executable:


add_library( auxlib )
target_sources( auxlib PRIVATE aux.cxx aux.h )
target_link_libraries( program PRIVATE auxlib )

36 Eijkhout – CMake tutorial – Fall 2023


Library during build, setup

Full configuration for an executable that uses a library:


1 cmake_minimum_required( VERSION 3.12 )
2 project( cmakeprogram VERSION 1.0 )
3

4 add_executable( program )
5 target_sources( program PRIVATE program.cxx )
6

7 add_library( auxlib )
8 target_sources( auxlib PRIVATE aux.cxx aux.h )
9

10 target_link_libraries( program PRIVATE auxlib )


11

12 install( TARGETS program DESTINATION . )

Library shared by default; see later.

37 Eijkhout – CMake tutorial – Fall 2023


Shared and static libraries

In the configuration file:


add_library( auxlib STATIC )
# or
add_library( auxlib SHARED )

(default shared if left out), or by adding a runtime flag


cmake -D BUILD_SHARED_LIBS=TRUE

Build both by having two lines, one for shared, one for static.
Related: the -fPIC compile option is set by
CMAKE_POSITION_INDEPENDENT_CODE:
cmake -D CMAKE_POSITION_INDEPENDENT_CODE=ON

38 Eijkhout – CMake tutorial – Fall 2023


Release a library

To have the library released too, use PUBLIC.


Add the library target to the install command.

39 Eijkhout – CMake tutorial – Fall 2023


Example: released library

1 cmake_minimum_required( VERSION 3.12 )


2 project( cmakeprogram VERSION 1.0 )
3

4 add_executable( program )
5 target_sources( program PRIVATE program.cxx )
6

7 add_library( auxlib STATIC )


8 target_sources( auxlib PRIVATE lib/aux.cxx lib/aux.h )
9

10 target_link_libraries( program PUBLIC auxlib )


11 target_include_directories( program PRIVATE lib )
12

13 install( TARGETS program DESTINATION bin )


14 install( TARGETS auxlib DESTINATION lib )
15 install( FILES lib/aux.h DESTINATION include )

Note the separate destination directories.

40 Eijkhout – CMake tutorial – Fall 2023


We are getting realistic

The previous setup was messy


Better handle the library through a recursive cmake
and make the usual lib include bin setup

41 Eijkhout – CMake tutorial – Fall 2023


Recursive setup, main directory

Declare that there is a directory to do recursive make:


1 cmake_minimum_required( VERSION 3.13 )
2 # needs >3.12 to let the executable target find the .h file
3 project( cmakeprogram VERSION 1.0 )
4

5 add_executable( program )
6 target_sources( program PRIVATE program.cxx )
7 add_subdirectory( lib )
8 target_include_directories(
9 program PUBLIC lib )
10 target_link_libraries( program PUBLIC auxlib )
11 install( TARGETS program DESTINATION bin )

(Note that the name of the library comes from the subdirectory)

42 Eijkhout – CMake tutorial – Fall 2023


Recursive setup, subdirectory

Installs into lib and include


1 cmake_minimum_required( VERSION 3.13 )
2 # needs >3.12 to let the executable target find the .h file
3

4 add_library( auxlib STATIC )


5 target_sources( auxlib
6 PRIVATE aux.cxx
7 PUBLIC aux.h )
8 install( TARGETS auxlib DESTINATION lib )
9 install( FILES aux.h DESTINATION include )

43 Eijkhout – CMake tutorial – Fall 2023


External libraries

Use LD_LIBRARY_PATH, or
use rpath.
(Apple note: forced to use second option)
set_target_properties(
${PROGRAM_NAME} PROPERTIES
BUILD_RPATH "${CATCH2_LIBRARY_DIRS};${FMTLIB_LIBRARY_DIRS}"
INSTALL_RPATH "${CATCH2_LIBRARY_DIRS};${FMTLIB_LIBRARY_DIRS}"
)

44 Eijkhout – CMake tutorial – Fall 2023


Install other project

include(ExternalProject)
ExternalProject_Add(googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG master
SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src"
BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
)

45 Eijkhout – CMake tutorial – Fall 2023


Help! I want people to use
my CMake package!

46 Eijkhout – CMake tutorial – Fall 2023


Making your package discoverable through pkgconfig

47 Eijkhout – CMake tutorial – Fall 2023


How does pkgconfig work?

Use the PKG_CONFIG_PATH variable:


$ module show cxxopts 2>&1 | grep -i pkg
prepend_path("PKG_CONFIG_PATH","/opt/cxxopts/intel23/lib64/pkgconfig")

48 Eijkhout – CMake tutorial – Fall 2023


Write your own .pc file

configure_file line in CMakeLists.txt:


configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.pc.in
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc
@ONLY)

49 Eijkhout – CMake tutorial – Fall 2023


Write your own .pc file’

The .pc.in file:


prefix="@CMAKE_INSTALL_PREFIX@"
exec_prefix="${prefix}"
libdir="${prefix}/lib"
includedir="${prefix}/include"

Name: @PROJECT_NAME@
Description: @CMAKE_PROJECT_DESCRIPTION@
Version: @PROJECT_VERSION@
Cflags: -I${includedir}
Libs: -L${libdir} -l@libtarget@

Note the initial cap!


Combination of built-in variables and your own:
set( libtarget auxlib )

50 Eijkhout – CMake tutorial – Fall 2023


Installing the pc file

install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc
DESTINATION share/pkgconfig
)

51 Eijkhout – CMake tutorial – Fall 2023


Example libraries

52 Eijkhout – CMake tutorial – Fall 2023


Parallelism

53 Eijkhout – CMake tutorial – Fall 2023


MPI from C

MPI has a module:


find_package( MPI )
target_include_directories(
${PROJECT_NAME} PUBLIC
${MPI_C_INCLUDE_DIRS} )
target_link_libraries(
${PROJECT_NAME} PUBLIC
${MPI_C_LIBRARIES} )

54 Eijkhout – CMake tutorial – Fall 2023


MPI from C++

find_package( MPI )
target_include_directories(
${PROJECT_NAME} PUBLIC
${MPI_CXX_INCLUDE_DIRS} )
target_link_libraries(
${PROJECT_NAME} PUBLIC
${MPI_CXX_LIBRARIES} )

55 Eijkhout – CMake tutorial – Fall 2023


MPI from Fortran90

find_package( MPI )
target_include_directories(
${PROJECT_NAME} PUBLIC
${MPI_INCLUDE_DIRS} )
target_link_directories(
${PROJECT_NAME} PUBLIC
${MPI_LIBRARY_DIRS} )
target_link_libraries(
${PROJECT_NAME} PUBLIC
${MPI_Fortran_LIBRARIES} )

56 Eijkhout – CMake tutorial – Fall 2023


MPI from Fortran2008

if( MPI_Fortran_HAVE_F08_MODULE )
else()
message( FATAL_ERROR "No f08 module for this MPI" )
endif()

57 Eijkhout – CMake tutorial – Fall 2023


MPL

find_package( mpl REQUIRED )


target_include_directories(
${PROJECT_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
mpl::mpl )
target_link_libraries(
${PROJECT_NAME} PUBLIC
mpl::mpl )

58 Eijkhout – CMake tutorial – Fall 2023


OpenMP from C

find_package(OpenMP)
target_link_libraries(
${PROJECT_NAME}
PUBLIC OpenMP::OpenMP_C )

59 Eijkhout – CMake tutorial – Fall 2023


OpenMP from C++

find_package(OpenMP)
if(OpenMP_CXX_FOUND)
else()
message( FATAL_ERROR "Could not find OpenMP" )
endif()
target_link_libraries(
${PROJECT_NAME}
PUBLIC OpenMP::OpenMP_CXX )

60 Eijkhout – CMake tutorial – Fall 2023


OpenMP from Fortran

enable_language(Fortran)
find_package(OpenMP)
target_link_libraries(
${PROJECT_NAME}
PUBLIC OpenMP::OpenMP_Fortran )

61 Eijkhout – CMake tutorial – Fall 2023


TBB

62 Eijkhout – CMake tutorial – Fall 2023


TBB

find_package(TBB REQUIRED)
target_link_libraries( ${PROJECT_NAME} PUBLIC TBB::tbb)

63 Eijkhout – CMake tutorial – Fall 2023


Kokkos

find_package(Kokkos REQUIRED)
target_link_libraries(myTarget Kokkos::kokkos)

Either set CMAKE_PREFIX_PATH or add


-DKokkos_ROOT=<Kokkos Install Directory>/lib64/cmake/Kokkos

Maybe:
-DCMAKE_CXX_COMPILER=<Kokkos Install Directory>/bin/
nvcc_wrapper

See https://kokkos.org/kokkos-core-wiki/ProgrammingGuide/
Compiling.html

64 Eijkhout – CMake tutorial – Fall 2023


Data packages

65 Eijkhout – CMake tutorial – Fall 2023


Hdf5

C:
find_package( PkgConfig REQUIRED )
pkg_check_modules( HDF REQUIRED hdf5 )
message( STATUS "Hdf5 includes: ${HDF_INCLUDE_DIRS}" )

target_include_directories(
${PROJECTNAME} PUBLIC
${HDF_INCLUDE_DIRS}
)

66 Eijkhout – CMake tutorial – Fall 2023


Netcdf

C:
find_package( PkgConfig REQUIRED )
pkg_check_modules( NETCDF REQUIRED netcdf )

target_include_directories(
${PROJECTNAME} PUBLIC
${NETCDF_INCLUDE_DIRS} )
target_link_libraries(
${PROJECTNAME} PUBLIC
${NETCDF_LIBRARIES} )
target_link_directories(
${PROJECTNAME} PUBLIC
${NETCDF_LIBRARY_DIRS} )
target_link_libraries(
${PROJECTNAME} PUBLIC netcdf )

67 Eijkhout – CMake tutorial – Fall 2023


Hdf5, Fortran

find_package( PkgConfig REQUIRED )


pkg_check_modules( NETCDFF REQUIRED netcdf-fortran )
pkg_check_modules( NETCDF REQUIRED netcdf )

target_include_directories(
${PROJECTNAME} PUBLIC
${NETCDFF_INCLUDE_DIRS}
)
target_link_libraries(
${PROJECTNAME} PUBLIC
${NETCDFF_LIBRARIES} ${NETCDF_LIBRARIES}
)
target_link_directories(
${PROJECTNAME} PUBLIC
${NETCDFF_LIBRARY_DIRS} ${NETCDF_LIBRARY_DIRS}
)
target_link_libraries(
${PROJECTNAME} PUBLIC netcdf )

68 Eijkhout – CMake tutorial – Fall 2023


HighFive

Third party C++ interface to hdf5


find_package( HighFive REQUIRED )
target_link_libraries( ${PROJECTNAME} HighFive)

69 Eijkhout – CMake tutorial – Fall 2023


More libraries

70 Eijkhout – CMake tutorial – Fall 2023


Package finding

Package dependent:
Sometimes through pkg-config:
find the .pc file
Sometimes through a Find.... module
see CMake documentation

71 Eijkhout – CMake tutorial – Fall 2023


Catch2

find_package( PkgConfig REQUIRED )


pkg_check_modules( CATCH2 REQUIRED catch2-with-main )
target_include_directories(
${PROGRAM_NAME} PUBLIC
${CATCH2_INCLUDE_DIRS}
)
target_link_directories(
${PROGRAM_NAME} PUBLIC
${CATCH2_LIBRARY_DIRS}
)
target_link_libraries(
${PROGRAM_NAME} PUBLIC
${CATCH2_LIBRARIES}
)

72 Eijkhout – CMake tutorial – Fall 2023


Cxxopts

Header-only:
find_package( PkgConfig REQUIRED )
pkg_check_modules( OPTS REQUIRED cxxopts )
target_include_directories(
${PROGRAM_NAME} PUBLIC
${OPTS_INCLUDE_DIRS}
)

73 Eijkhout – CMake tutorial – Fall 2023


Eigen

Header-only:
cmake_minimum_required( VERSION 3.12 )
project( eigentest )

find_package( PkgConfig REQUIRED )


pkg_check_modules( EIGEN REQUIRED eigen3 )

add_executable( eigentest )
target_sources( eigentest PRIVATE eigentest.cxx )
target_include_directories(
myprogram PUBLIC
${EIGEN_INCLUDE_DIRS})

74 Eijkhout – CMake tutorial – Fall 2023


Fmtlib

find_package( PkgConfig REQUIRED )


pkg_check_modules( FMTLIB REQUIRED fmt )
target_include_directories(
${PROGRAM_NAME} PUBLIC ${FMTLIB_INCLUDE_DIRS}
)
target_link_directories(
${PROGRAM_NAME} PUBLIC ${FMTLIB_LIBRARY_DIRS}
)
target_link_libraries(
${PROGRAM_NAME} PUBLIC ${FMTLIB_LIBRARIES}
)

75 Eijkhout – CMake tutorial – Fall 2023


Range-v3

Has its own module:


find_package( range-v3 REQUIRED )
target_link_libraries(
${PROGRAM_NAME} PUBLIC range-v3::range-v3 )

76 Eijkhout – CMake tutorial – Fall 2023

You might also like