電子状態計算パッケージecaljのCMakeList.txtを添付します。(https://github.com/tkotani/ecalj/tree/experimental)
以前は異常に長いMakefileを書いてたしdependency checkerも自前だったのでだいぶ改善されました。検索したりgithub copilotに聞いたりして自己流で書いているのでなんともわからないでやってるところもあります。コメント等,教えていただけるとうれしいです。
messageのところにあるようにSRC/execでたとえば
FC=gfortran DEBUG=1 cmake .
として利用します。FCをあたえないとメッセージ出して終了します。
cmakeでMakefileができるのですが、おすすめのやり方は
VERBOSE=1 make -j |grep -v shared |grep mpi
です。コンパイルオプションを表示しながら進みます。パーセント表示はうれしいようなうれしくないようなです。
-
SRC/*/*.f90はみなコンパイルします。fortranソースコードは一つのライブラリにして、単純な複数のメイン関数から呼び出す仕掛けです。
-
マシンごとに-O0コンパイルしないといけないソースがあったりするわけですが、それを書き込んでいます。
-
show_programinfo.f90はgit情報を取り込んだfortran fileなんですー他のソースファイルが更新されてないなら作り直さないようにしたいーが、それができてません。
-
FCはどうも特殊な環境変数として扱われるようで,以下のようにFCMODにコピーしとかないと勝手にフルパス展開されちゃったりします。
-
ecaljでは複数のメイン関数がありますが、たとえばSRC/subroutines/main_lmf.f90が実質のメイン関数の一つです。subroutine lmf(comm) bind(C)が冒頭にあります。それをmain/lmf.f90が呼び出します。lmf.f90がbind(C)になっているのはmpi4pyを想定しています。commはコミュニケータでmpi4pyから渡します。渡さない場合はmain_lmf.f90内でcomm_worldを利用します。fortranの複数のメイン関数SRC/subroutines/main_foobar.f90はfotranのメインからでもpythonのメインからでも呼び出せます。
(pythonをメインにするやり方は進展中で実験段階です)。 -
ifortでDEBUGがないとき、-O2 -traceback -gでも速度は変わらないのかもしれない。
-
./dummy.f90は、lddをとってmath libraryのパスを検索するためのものです。
# Make libecaljF.so and all binaries. Run > FC=gfortran cmake . for generating make file
# run >VERBOSE=1 make to see detailed compile options
cmake_minimum_required(VERSION 3.2)
if(DEFINED CACHE{FC} OR DEFINED ENV{FC})
set(FC $ENV{FC})
else()
message("--- ")
message("=== Your choices to run cmake are: ===")
message(" >FC=ifort cmake .")
message(" >FC=ifort DEBUG=1 cmake .")
message(" >FC=gfortran cmake .")
message(" >FC=gfortran DEBUG=1 cmake .")
message(" >FC=nvfortran cmake .")
message(" >FC=nvfortran DEBUG=1 cmake .")
message("You may run >VERBOSE=1 make -j, for detailed make messages.")
message("Note that '>rm -rf CMakeCache.txt CMakeFiles' is needed for starting over!")
message(FATAL_ERROR "==> FC=foobar is needed! e.g, FC=gfortran cmake .")
endif()
set(FCMOD ${FC})
Project (ecalj)
#SET(CMAKE_VERBOSE_MAKEFILE ON)
enable_language(Fortran)
# Note: we always renew show_programinfo.f90 because of Makeshow is always invoked. How to improve this?
add_custom_target(show_programinfo.f90 ALL COMMAND make -f Makeshow WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
file(GLOB SOURCES "../subroutines/*.f90" "../wanniergw/*.f90" "../subroutines/show_programinfo.f90") # source files
file(GLOB MAINS "../main/*.f90") # main source files
set(LIBRARY_NAME ecaljF) # library name is libecaljF.so
#if(DEFINED CACHE{FC} OR DEFINED ENV{FC})
# set(FC $ENV{FC})
#else()
# set(FC "gfortran") #default
#endif()
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) # directory for *.so
set(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/${FCMOD}/mod) # directory for *.mod
### show_programinfo.f90 get date and so on for binary info. This should be newer than others ###
### but I don't know how to do it. So I use add_custom_target with ALLch
#find_package(BLAS)
#find_package(MPI)
#find_package(LAPACK)
#message(STATUS ${BLAS_LIBARARIES})
#message(STATUS ${LAPACK})
if(DEFINED CACHE{DEBUG} OR DEFINED ENV{DEBUG})
set(DEBUG $ENV{DEBUG})
endif()
message(STATUS "DEBUG= ${DEBUG}")
### compile options ############################################################
if(FC MATCHES "gfortran")
set(CMAKE_Fortran_COMPILER mpif90) # compiler
set(CMAKE_Fortran_FLAGS "-g -fimplicit-none -finit-integer=NaN -finit-real=NaN -fPIC") # compile flags
set(LIB ${LIBRARY_NAME} -lmkl_rt) #set LIB variable
add_link_options(-lmkl_rt)
elseif(FC MATCHES "ifort")
set(CMAKE_Fortran_COMPILER mpiifort) # compiler
set(CMAKE_Fortran_FLAGS "-init:snan -fPIC -assume byterecl") # compile flags
set(LIB ${LIBRARY_NAME} -mkl) #set LIB variable
add_link_options(-mkl)
elseif(FC MATCHES "nvfortran")
set(CMAKE_Fortran_COMPILER mpifort) # compiler
set(CMAKE_Fortran_FLAGS "-fPIC") #"-Mvect=simd -mcmodel=medium -fPIC") # compile flags
set(LIB ${LIBRARY_NAME} ) #-mkl) #set LIB variable
add_link_options(-lmkl_intel_lp64 -lmkl_sequential -lmkl_core)
endif()
### source-dependent compile options
if(FC MATCHES "gfortran" AND DEFINED DEBUG)
message(STATUS "===== gfortran debug =======================")
foreach(target IN ITEMS ${SOURCES})
set_source_files_properties(${target} PROPERTIES COMPILE_FLAGS "-O0")
endforeach()
elseif(FC MATCHES "gfortran")
message(STATUS "===== gfortran release =======================")
foreach(target IN ITEMS ${SOURCES})
if(${target} MATCHES "../subroutines/mkqp.f90" OR ${target} MATCHES "../wannier/iopen.f90" )
set_source_files_properties(${target} PROPERTIES COMPILE_FLAGS "-O0")
else()
set_source_files_properties(${target} PROPERTIES COMPILE_FLAGS "-O2")
endif()
endforeach()
elseif(FC MATCHES "ifort" AND DEFINED DEBUG)
message(STATUS "===== ifort debug =======================")
foreach(target IN ITEMS ${SOURCES})
set_source_files_properties(${target} PROPERTIES COMPILE_FLAGS "-O0 -g -traceback")
endforeach()
elseif(FC MATCHES "ifort")
message(STATUS "====== ifort release =======================")
foreach(target IN ITEMS ${SOURCES})
if(${target} MATCHES "../subroutines/m_qplist.f90") # OR ${target} MATCHES "../subroutines/x0kf_v4h.f90" )
set_source_files_properties(${target} PROPERTIES COMPILE_FLAGS "-O0")
else()
set_source_files_properties(${target} PROPERTIES COMPILE_FLAGS "-O2")
endif()
endforeach()
elseif(FC MATCHES "nvfortran" AND DEFINED DEBUG)
message(STATUS "====== nvfortran debug =======================")
foreach(target IN ITEMS ${SOURCES})
set_source_files_properties(${target} PROPERTIES COMPILE_FLAGS "-C -g -traceback -O2") #why -O2 needed here???
endforeach()
elseif(FC MATCHES "nvfortran")
message(STATUS "====== nvfortran release =======================")
foreach(target IN ITEMS ${SOURCES})
if(${target} MATCHES "../subroutines/pwmat.f90"
OR ${target} MATCHES "../subroutines/rseq.f90")
set_source_files_properties(${target} PROPERTIES COMPILE_FLAGS "-C -g -traceback -O0")
else()
set_source_files_properties(${target} PROPERTIES COMPILE_FLAGS "-O2")
endif()
endforeach()
endif()
#For setting mkl location
add_executable(dummy ./dummy.f90 ) # exe
target_link_libraries(dummy ${LIB} ${BLAS} ${MPI}) #linked
#add_custom_target(fcheck ALL COMMAND ldd dummy|grep mkl >mklloc.txt WORKING_DIRECTORY ${CMAKE_BINARY_DIR} DEPENDS dummy)
# Generate library and binaries ###############################
add_library(${LIBRARY_NAME} SHARED ${SOURCES}) # Library
foreach(target IN ITEMS ${MAINS}) #main routines
get_filename_component(exename ${target} NAME_WE ) #set DIR variable
add_executable(${exename} ${target} ) # exe
target_link_libraries(${exename} ${LIB} ${BLAS} ${MPI}) #linked
endforeach()
#set(BINDIR $ENV{HOME}/bin)
#message(STATUS "BINDIR = ${BINDIR}")
#add_custom_target(inst cp `find . -mindepth 1 -maxdepth 1 -executable -type f` ${BINDIR})