Open nenanth opened 8 years ago
If the SET_COMPILE_FLAG
function is called with the REQUIRED
option, then it will fail if no valid flags are found. In the template, the only calls with REQUIRED
are the ones that set the optimization level... for DEBUG
this would be either -O0
or /Od
.
If you remove REQUIRED
does it still work?
I just took a look at the pgfortran
manual and it seems to support the -O0
, so I will need you to supply extra information for further help.
So I did a little debugging, and it appears that pgfortran is not throwing up one of the recognized error messages on my system for anything starting with "/" (written specifically for windows-ifort). Instead, the compilation messages for the same program fool it into believing that flags like "/O0" (slash oh-zero) are valid options. I fixed it by checking for OS type first, and using it as a branch to test the windows-ifort flags separately from the rest.
Below is my modified version of SetFortranFlags.cmake:
#==============================================================
# Determine and set the Fortran compiler flags we want
#==============================================================
#==============================================================
# Make sure that the default build type is RELEASE if not specified.
#==============================================================
INCLUDE(${CMAKE_MODULE_PATH}/SetCompileFlag.cmake)
#==============================================================
# Make sure the build type is uppercase
#==============================================================
STRING(TOUPPER "${CMAKE_BUILD_TYPE}" BT)
IF(BT STREQUAL "RELEASE")
SET(CMAKE_BUILD_TYPE RELEASE CACHE STRING
"Choose the type of build, options are DEBUG, RELEASE, or TESTING."
FORCE)
MESSAGE(STATUS "CMAKE BUILD TYPE RELEASE SELECTED")
ELSEIF(BT STREQUAL "DEBUG")
SET (CMAKE_BUILD_TYPE DEBUG CACHE STRING
"Choose the type of build, options are DEBUG, RELEASE, or TESTING."
FORCE)
MESSAGE(STATUS "CMAKE BUILD TYE DEBUG SELECTED")
ELSEIF(BT STREQUAL "TESTING")
SET (CMAKE_BUILD_TYPE TESTING CACHE STRING
"Choose the type of build, options are DEBUG, RELEASE, or TESTING."
FORCE)
MESSAGE(STATUS "CMAKE BUILD TYPE TESTING SELECTED")
ELSEIF(NOT BT)
SET(CMAKE_BUILD_TYPE RELEASE CACHE STRING
"Choose the type of build, options are DEBUG, RELEASE, or TESTING."
FORCE)
MESSAGE(STATUS "CMAKE_BUILD_TYPE not given, defaulting to RELEASE")
ELSE()
MESSAGE(FATAL_ERROR "CMAKE_BUILD_TYPE not valid, choices are DEBUG, RELEASE, or TESTING")
ENDIF(BT STREQUAL "RELEASE")
#==============================================================
# If the compiler flags have already been set, return now
#==============================================================
IF(CMAKE_Fortran_FLAGS_RELEASE AND CMAKE_Fortran_FLAGS_TESTING AND CMAKE_Fortran_FLAGS_DEBUG)
RETURN ()
ENDIF(CMAKE_Fortran_FLAGS_RELEASE AND CMAKE_Fortran_FLAGS_TESTING AND CMAKE_Fortran_FLAGS_DEBUG)
#==============================================================
# Determine the appropriate flags for this compiler for each build type.
# For each option type, a list of possible flags is given that work
# for various compilers. The first flag that works is chosen.
# If none of the flags work, nothing is added (unless the REQUIRED
# flag is given in the call). This way unknown compiles are supported.
#==============================================================
#==============================================================
### GENERAL FLAGS ###
#==============================================================
#==============================================================
# Don't add underscores in symbols for C-compatability
#==============================================================
SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}"
Fortran "-fno-underscoring")
#==============================================================
# There is some bug where -march=native doesn't work on Mac
#==============================================================
IF(APPLE)
SET(GNUNATIVE "-mtune=native")
ELSE()
SET(GNUNATIVE "-march=native")
ENDIF()
#==============================================================
# Define the operating system
#==============================================================
SET(OS ${CMAKE_SYSTEM_NAME})
SET(FC ${CMAKE_Fortran_COMPILER})
STRING(TOUPPER "${OS}" OS)
STRING(TOUPPER "${FC}" FC)
SET(Wintel FALSE)
IF(${OS} STREQUAL "WINDOWS")
IF(${FC} MATCHES "INTEL")
SET(Wintel TRUE)
ENDIF()
ENDIF()
MESSAGE("The Operating System Type is " ${OS})
MESSAGE("The Fortran Compiler is " ${FC})
#==============================================================
# Optimize for the host's architecture
#==============================================================
IF(${Wintel})
SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}"
Fortran "/QxHost" # Intel Windows
)
ELSE()
SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}"
Fortran "-xHost" # Intel
${GNUNATIVE} # GNU
"-ta=host" # Portland Group
)
ENDIF()
#==============================================================
### DEBUG FLAGS ###
#==============================================================
# NOTE: debugging symbols (-g or /debug:full) are already on by default
#==============================================================
# Disable optimizations
#==============================================================
IF(${Wintel})
SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}"
Fortran REQUIRED "/Od" # Intel Windows
)
ELSE()
SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}"
Fortran REQUIRED "-O0" # All compilers not on Windows
)
ENDIF()
#==============================================================
# Turn on all warnings
#==============================================================
IF(OS STREQUAL "WINDOWS")
SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}"
Fortran "/warn:all" # Intel Windows
)
ELSE()
SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}"
Fortran "-warn all" # Intel
"-Wall" # GNU
# Portland Group (on by default)
)
ENDIF()
#==============================================================
# Traceback
#==============================================================
IF(${Wintel})
SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}"
Fortran "/traceback" # Intel Windows
)
ELSE()
SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}"
Fortran "-traceback" # Intel/Portland Group
"-fbacktrace" # GNU (gfortran)
"-ftrace=full" # GNU (g95)
)
ENDIF()
#==============================================================
# Check array bounds
#==============================================================
IF(${Wintel})
SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}"
Fortran "/check:bounds" # Intel Windows
)
ELSE()
SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG}"
Fortran "-check bounds" # Intel
"-fcheck=bounds" # GNU (New style)
"-fbounds-check" # GNU (Old style)
"-Mbounds" # Portland Group
)
ENDIF()
#==============================================================
### TESTING FLAGS ###
#==============================================================
#==============================================================
# Optimizations
#==============================================================
IF(${Wintel})
SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_TESTING "${CMAKE_Fortran_FLAGS_TESTING}"
Fortran REQUIRED "/O2" # Intel Windows
)
ELSE()
SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_TESTING "${CMAKE_Fortran_FLAGS_TESTING}"
Fortran REQUIRED "-O2" # All compilers not on Windows
)
ENDIF()
#==============================================================
### RELEASE FLAGS ###
#==============================================================
# NOTE: agressive optimizations (-O3) are already turned on by default
#==============================================================
# Unroll loops
#==============================================================
IF(${Wintel})
SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}"
Fortran "/unroll" # Intel Windows
)
ELSE()
SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}"
Fortran "-funroll-loops" # GNU
"-unroll" # Intel
"-Munroll" # Portland Group
)
ENDIF()
#==============================================================
# Inline functions
#==============================================================
IF(${Wintel})
SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}"
Fortran "/Qinline" # Intel Windows
)
ELSE()
SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}"
Fortran "-inline" # Intel
"-finline-functions" # GNU
"-Minline" # Portland Group
)
ENDIF()
#==============================================================
# Interprocedural (link-time) optimizations
#==============================================================
IF(${Wintel})
SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}"
Fortran "/Qipo" # Intel Windows
)
ELSE()
SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}"
Fortran "-ipo" # Intel
"-flto" # GNU
"-Mipa" # Portland Group
)
ENDIF()
#==============================================================
# Single-file optimizations
#==============================================================
IF(${Wintel})
SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}"
Fortran "/Qip" # Intel Windows
)
ELSE()
SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}"
Fortran "-ip" # Intel
)
ENDIF()
#==============================================================
# Turn off loop vectorization diagnostics; parallelization done by AS
#==============================================================
#IF(${Wintel})
# SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}"
# Fortran "/Qvec-report0" # Intel Windows
# )
#ELSE()
# SET_COMPILE_FLAG(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE}"
# Fortran "-vec-report0" # Intel
# "-Mvect" # Portland Group
# )
#ENDIF()
Is there a reason you didn't modify SetCompileFlag.cmake
with the message the pgfortran
was giving on compile error? I believe that would have been less work.
pgfortran seemed to think that the "slash" referred to a path, instead of a compilation option.
I didn't want any (future) compiler versions to throw errors based on OS-specific flags. The solution above feels more robust, because it avoids combinations of flags/OS's that are known to be incompatible (as opposed to triggers based on specific errors).
The exact error is pasted below: pgfortran /Qhost a.f90 a.f90: /usr/bin/ld: cannot find /Qhost: No such file or directory
The string "No such file or directory" could be added to the FAIL_REGEX
in SetCompileFlag.cmake
to solve the problem.
I am glad you have a solution that works for you. I am not convinced this is the most robust solution because it assumes that Intel Windows is the only compiler the uses the /
prefix, which may not be true. I had only checked a limited number of compilers when I made the template.
The try: except:
methodology I used mimics what Kitware does in FindOpenMP.cmake, and my assumption was that if this method works for them, it would work for me as well.
Having said all that, if you think your solution is better then make a pull request and I will consider accepting the change.
makes sense. I'll experiment with it a bit more on all 3 OS's, and see whether the solution covers all cases. After that, I can say with a little more confidence that it's a working solution.
@nenanth Did this issue ever get resolved? I'm thinking of putting together a pull request to modernize this template per #3 and would like to incorporate any findings. Or if you can submit a pull request yourself, that would be great!
@emanspeaks so far I've gotten by with the code posted above; havent dug into CMake too much because I'm not super familiar with the language.. my patch seems to work OK on a few different machines. Also, I was able make only a few tests on windows before the infamous Fall Creators update screwed up a few things and I moved away from the OS altogether.
@emanspeaks Based on your willingness to tackle #3 I would guess you are actually versed in modern CMake style. I don't think there are many out there that have that knowledge AND Fortran knowledge, so I would say just go for it and add this fix into your PR.
because of the new way that compiler flags are set in modern CMake, this issue would become obsolete after #4 is merged.
I tried the template code as is, and it worked fine for gfortran on Ubuntu 14.04
When i tried it with ifort, things were good too.. $ FC=ifort cmake .. The Makefile was created and everything worked.
However, after flushing the build directory, I tried it with the PGI compiler to get (FC=pgfortran cmake ..)
I placed print statements in cmake/Modules/SetFortranFlags.cmake, and it seems like there is an issue with setting the first debug flag with the PGI compiler. Not sure what's going on under the hood, but thought it might be worth digging into.