diff options
author | David Cole <david.cole@kitware.com> | 2012-02-14 21:16:15 (GMT) |
---|---|---|
committer | CMake Topic Stage <kwrobot@kitware.com> | 2012-02-14 21:16:15 (GMT) |
commit | c69a20573ed332ca855cdac3f8c03e7df2e46f8c (patch) | |
tree | d4b0364da48adaac5d836db0422c14436ff5b386 | |
parent | d3d79c8b80aa606b12ebea3cb32b13e9bd15e321 (diff) | |
parent | 1e16406dc9a8c5bdad7adbed8c3b6cee0a7020d0 (diff) | |
download | CMake-c69a20573ed332ca855cdac3f8c03e7df2e46f8c.zip CMake-c69a20573ed332ca855cdac3f8c03e7df2e46f8c.tar.gz CMake-c69a20573ed332ca855cdac3f8c03e7df2e46f8c.tar.bz2 |
Merge topic 'cmake_add_fortran_subdirectory'
1e16406 CMakeAddFortranSubdirectory: Add NO_EXTERNAL_INSTALL option
6f6891b CMakeAddFortranSubdirectory: Always parse arguments
48a09f8 CMakeAddFortranSubdirectory: Make IMPORTED targets GLOBAL
067c1f4 VSGNUFortran: Disable test in special cases
bd69e1c VSGNUFortran: Add special case for SunPro Fortran runtime library
414a780 CMakeAddFortranSubdirectory: Validate gfortran architecture
7e0d9f1 CMakeAddFortranSubdirectory: Find gfortran in PATH
d6b0312 CMakeAddFortranSubdirectory: Fix documentation format and typos
e4ae038 CMakeAddFortranSubdirectory: Allow full paths to directories
538c345 Add CMakeAddFortranSubdirectory to use MinGW gfortran in VS
3c6af5f Merge branch 'add-CheckLanguage-module' into CMakeAddFortranSubdirectory
-rw-r--r-- | Modules/CMakeAddFortranSubdirectory.cmake | 206 | ||||
-rw-r--r-- | Modules/CMakeAddFortranSubdirectory/build_mingw.cmake.in | 2 | ||||
-rw-r--r-- | Modules/CMakeAddFortranSubdirectory/config_mingw.cmake.in | 9 | ||||
-rw-r--r-- | Tests/CMakeLists.txt | 26 | ||||
-rw-r--r-- | Tests/VSGNUFortran/CMakeLists.txt | 26 | ||||
-rw-r--r-- | Tests/VSGNUFortran/c_code/CMakeLists.txt | 2 | ||||
-rw-r--r-- | Tests/VSGNUFortran/c_code/main.c | 7 | ||||
-rw-r--r-- | Tests/VSGNUFortran/runtest.cmake.in | 23 | ||||
-rw-r--r-- | Tests/VSGNUFortran/subdir/CMakeLists.txt | 16 | ||||
-rw-r--r-- | Tests/VSGNUFortran/subdir/fortran/CMakeLists.txt | 46 | ||||
-rw-r--r-- | Tests/VSGNUFortran/subdir/fortran/hello.f | 7 | ||||
-rw-r--r-- | Tests/VSGNUFortran/subdir/fortran/world.f | 6 |
12 files changed, 376 insertions, 0 deletions
diff --git a/Modules/CMakeAddFortranSubdirectory.cmake b/Modules/CMakeAddFortranSubdirectory.cmake new file mode 100644 index 0000000..ddb79fb --- /dev/null +++ b/Modules/CMakeAddFortranSubdirectory.cmake @@ -0,0 +1,206 @@ +# - Use MinGW gfortran from VS if a fortran compiler is not found. +# The 'add_fortran_subdirectory' function adds a subdirectory +# to a project that contains a fortran only sub-project. The module +# will check the current compiler and see if it can support fortran. +# If no fortran compiler is found and the compiler is MSVC, then +# this module will find the MinGW gfortran. It will then use +# an external project to build with the MinGW tools. It will also +# create imported targets for the libraries created. This will only +# work if the fortran code is built into a dll, so BUILD_SHARED_LIBS +# is turned on in the project. In addition the CMAKE_GNUtoMS option +# is set to on, so that the MS .lib files are created. +# Usage is as follows: +# cmake_add_fortran_subdirectory( +# <subdir> # name of subdirectory +# PROJECT <project_name> # project name in subdir top CMakeLists.txt +# ARCHIVE_DIR <dir> # dir where project places .lib files +# RUNTIME_DIR <dir> # dir where project places .dll files +# LIBRARIES <lib>... # names of library targets to import +# LINK_LIBRARIES # link interface libraries for LIBRARIES +# [LINK_LIBS <lib> <dep>...]... +# CMAKE_COMMAND_LINE ... # extra command line flags to pass to cmake +# NO_EXTERNAL_INSTALL # skip installation of external project +# ) +# Relative paths in ARCHIVE_DIR and RUNTIME_DIR are interpreted with respect +# to the build directory corresponding to the source directory in which the +# function is invoked. +# +# Limitations: +# +# NO_EXTERNAL_INSTALL is required for forward compatibility with a +# future version that supports installation of the external project +# binaries during "make install". + +#============================================================================= +# Copyright 2011-2012 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + + +set(_MS_MINGW_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}) +include(CheckLanguage) +include(ExternalProject) +include(CMakeParseArguments) + +function(_setup_mingw_config_and_build source_dir) + # Look for a MinGW gfortran. + find_program(MINGW_GFORTRAN + NAMES gfortran + PATHS + c:/MinGW/bin + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MinGW;InstallLocation]/bin" + ) + if(NOT MINGW_GFORTRAN) + message(FATAL_ERROR + "gfortran not found, please install MinGW with the gfortran option." + "Or set the cache variable MINGW_GFORTRAN to the full path. " + " This is required to build") + endif() + + # Validate the MinGW gfortran we found. + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(_mingw_target "Target:.*64.*mingw") + else() + set(_mingw_target "Target:.*mingw32") + endif() + execute_process(COMMAND "${MINGW_GFORTRAN}" -v + ERROR_VARIABLE out ERROR_STRIP_TRAILING_WHITESPACE) + if(NOT "${out}" MATCHES "${_mingw_target}") + string(REPLACE "\n" "\n " out " ${out}") + message(FATAL_ERROR + "MINGW_GFORTRAN is set to\n" + " ${MINGW_GFORTRAN}\n" + "which is not a MinGW gfortran for this architecture. " + "The output from -v does not match \"${_mingw_target}\":\n" + "${out}\n" + "Set MINGW_GFORTRAN to a proper MinGW gfortran for this architecture." + ) + endif() + + # Configure scripts to run MinGW tools with the proper PATH. + get_filename_component(MINGW_PATH ${MINGW_GFORTRAN} PATH) + file(TO_NATIVE_PATH "${MINGW_PATH}" MINGW_PATH) + string(REPLACE "\\" "\\\\" MINGW_PATH "${MINGW_PATH}") + configure_file( + ${_MS_MINGW_SOURCE_DIR}/CMakeAddFortranSubdirectory/config_mingw.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/config_mingw.cmake + @ONLY) + configure_file( + ${_MS_MINGW_SOURCE_DIR}/CMakeAddFortranSubdirectory/build_mingw.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/build_mingw.cmake + @ONLY) +endfunction() + +function(_add_fortran_library_link_interface library depend_library) + set_target_properties(${library} PROPERTIES + IMPORTED_LINK_INTERFACE_LIBRARIES_NOCONFIG "${depend_library}") +endfunction() + + +function(cmake_add_fortran_subdirectory subdir) + # Parse arguments to function + set(options NO_EXTERNAL_INSTALL) + set(oneValueArgs PROJECT ARCHIVE_DIR RUNTIME_DIR) + set(multiValueArgs LIBRARIES LINK_LIBRARIES CMAKE_COMMAND_LINE) + cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + if(NOT ARGS_NO_EXTERNAL_INSTALL) + message(FATAL_ERROR + "Option NO_EXTERNAL_INSTALL is required (for forward compatibility) " + "but was not given." + ) + endif() + + # if we are not using MSVC without fortran support + # then just use the usual add_subdirectory to build + # the fortran library + check_language(Fortran) + if(NOT (MSVC AND (NOT CMAKE_Fortran_COMPILER))) + add_subdirectory(${subdir}) + return() + endif() + + # if we have MSVC without Intel fortran then setup + # external projects to build with mingw fortran + + set(source_dir "${CMAKE_CURRENT_SOURCE_DIR}/${subdir}") + set(project_name "${ARGS_PROJECT}") + set(library_dir "${ARGS_ARCHIVE_DIR}") + set(binary_dir "${ARGS_RUNTIME_DIR}") + set(libraries ${ARGS_LIBRARIES}) + # use the same directory that add_subdirectory would have used + set(build_dir "${CMAKE_CURRENT_BINARY_DIR}/${subdir}") + foreach(dir_var library_dir binary_dir) + if(NOT IS_ABSOLUTE "${${dir_var}}") + get_filename_component(${dir_var} + "${CMAKE_CURRENT_BINARY_DIR}/${${dir_var}}" ABSOLUTE) + endif() + endforeach() + # create build and configure wrapper scripts + _setup_mingw_config_and_build(${source_dir}) + # create the external project + externalproject_add(${project_name}_build + SOURCE_DIR ${source_dir} + BINARY_DIR ${build_dir} + CONFIGURE_COMMAND ${CMAKE_COMMAND} + -P ${CMAKE_CURRENT_BINARY_DIR}/config_mingw.cmake + BUILD_COMMAND ${CMAKE_COMMAND} + -P ${CMAKE_CURRENT_BINARY_DIR}/build_mingw.cmake + INSTALL_COMMAND "" + ) + # make the external project always run make with each build + externalproject_add_step(${project_name}_build forcebuild + COMMAND ${CMAKE_COMMAND} + -E remove + ${CMAKE_CURRENT_BUILD_DIR}/${project_name}-prefix/src/${project_name}-stamp/${project_name}-build + DEPENDEES configure + DEPENDERS build + ALWAYS 1 + ) + # create imported targets for all libraries + foreach(lib ${libraries}) + add_library(${lib} SHARED IMPORTED GLOBAL) + set_property(TARGET ${lib} APPEND PROPERTY IMPORTED_CONFIGURATIONS NOCONFIG) + set_target_properties(${lib} PROPERTIES + IMPORTED_IMPLIB_NOCONFIG "${library_dir}/lib${lib}.lib" + IMPORTED_LOCATION_NOCONFIG "${binary_dir}/lib${lib}.dll" + ) + add_dependencies(${lib} ${project_name}_build) + endforeach() + + # now setup link libraries for targets + set(start FALSE) + set(target) + foreach(lib ${ARGS_LINK_LIBRARIES}) + if("${lib}" STREQUAL "LINK_LIBS") + set(start TRUE) + else() + if(start) + if(DEFINED target) + # process current target and target_libs + _add_fortran_library_link_interface(${target} "${target_libs}") + # zero out target and target_libs + set(target) + set(target_libs) + endif() + # save the current target and set start to FALSE + set(target ${lib}) + set(start FALSE) + else() + # append the lib to target_libs + list(APPEND target_libs "${lib}") + endif() + endif() + endforeach() + # process anything that is left in target and target_libs + if(DEFINED target) + _add_fortran_library_link_interface(${target} "${target_libs}") + endif() +endfunction() diff --git a/Modules/CMakeAddFortranSubdirectory/build_mingw.cmake.in b/Modules/CMakeAddFortranSubdirectory/build_mingw.cmake.in new file mode 100644 index 0000000..55b271a --- /dev/null +++ b/Modules/CMakeAddFortranSubdirectory/build_mingw.cmake.in @@ -0,0 +1,2 @@ +set(ENV{PATH} "@MINGW_PATH@\;$ENV{PATH}") +execute_process(COMMAND "@CMAKE_COMMAND@" --build . ) diff --git a/Modules/CMakeAddFortranSubdirectory/config_mingw.cmake.in b/Modules/CMakeAddFortranSubdirectory/config_mingw.cmake.in new file mode 100644 index 0000000..97f6769 --- /dev/null +++ b/Modules/CMakeAddFortranSubdirectory/config_mingw.cmake.in @@ -0,0 +1,9 @@ +set(ENV{PATH} "@MINGW_PATH@\;$ENV{PATH}") +set(CMAKE_COMMAND_LINE "@ARGS_CMAKE_COMMAND_LINE@") +execute_process( + COMMAND "@CMAKE_COMMAND@" "-GMinGW Makefiles" + -DCMAKE_Fortran_COMPILER:PATH=@MINGW_GFORTRAN@ + -DBUILD_SHARED_LIBS=ON + -DCMAKE_GNUtoMS=ON + ${CMAKE_COMMAND_LINE} + "@source_dir@") diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 906b40d..9c97828 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -163,6 +163,32 @@ IF(BUILD_TESTING) IF(CMAKE_Fortran_COMPILER) ADD_TEST_MACRO(FortranOnly FortranOnly) ENDIF() + # test Visual Studio GNU Fortran mixing with cmake_add_fortran_subdirectory + # run this project if we have a working fortran compiler or + # the test is enabled with CMAKE_TEST_CMAKE_ADD_FORTRAN cache variable. + # If you enable the test, CMake should find the MinGW fortran install, + # or in some cases you might need to set the PATH so that cmake can find + # the gfortran from mingw. + IF(CMAKE_Fortran_COMPILER OR CMAKE_TEST_CMAKE_ADD_FORTRAN) + SET(CMAKE_SKIP_VSGNUFortran FALSE) + # disable test for apple builds using ifort if they are building + # more than one architecture, as ifort does not support that. + IF(APPLE AND (CMAKE_Fortran_COMPILER MATCHES ifort)) + LIST(LENGTH CMAKE_OSX_ARCHITECTURES len) + IF("${len}" GREATER 1) + MESSAGE(STATUS "Skip VSGNUFortran for ifort dual cpu mac build") + SET(CMAKE_SKIP_VSGNUFortran TRUE) + ENDIF() + ENDIF() + IF((CMAKE_C_COMPILER MATCHES lsb) + AND (CMAKE_Fortran_COMPILER MATCHES ifort)) + MESSAGE(STATUS "Skip VSGNUFortran for ifort and lsb compilers") + SET(CMAKE_SKIP_VSGNUFortran TRUE) + ENDIF() + IF(NOT CMAKE_SKIP_VSGNUFortran) + ADD_TEST_MACRO(VSGNUFortran ${CMAKE_COMMAND} -P runtest.cmake) + ENDIF() + ENDIF() ADD_TEST_MACRO(COnly COnly) ADD_TEST_MACRO(CxxOnly CxxOnly) ADD_TEST_MACRO(IPO COnly/COnly) diff --git a/Tests/VSGNUFortran/CMakeLists.txt b/Tests/VSGNUFortran/CMakeLists.txt new file mode 100644 index 0000000..229c315 --- /dev/null +++ b/Tests/VSGNUFortran/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 2.8) +project(VSGNUFortran) + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") + +# force the executable to be put out of Debug/Release dir +# because gmake build of fortran will not be in a config +# directory, and for easier testing we want the exe and .dll +# to be in the same directory. +if(CMAKE_CONFIGURATION_TYPES) + foreach(config ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER "${config}" config) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${config} + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + endforeach() +endif() + +add_subdirectory(subdir) +include_directories(${VSGNUFortran_BINARY_DIR}/subdir/fortran) +add_subdirectory(c_code) +# use a cmake script to run the executable so that PATH +# can be set with the MinGW/bin in it, and the fortran +# runtime libraries can be found. +configure_file(runtest.cmake.in runtest.cmake @ONLY) diff --git a/Tests/VSGNUFortran/c_code/CMakeLists.txt b/Tests/VSGNUFortran/c_code/CMakeLists.txt new file mode 100644 index 0000000..27d22fd --- /dev/null +++ b/Tests/VSGNUFortran/c_code/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(c_using_fortran main.c) +target_link_libraries(c_using_fortran hello) diff --git a/Tests/VSGNUFortran/c_code/main.c b/Tests/VSGNUFortran/c_code/main.c new file mode 100644 index 0000000..391bf26 --- /dev/null +++ b/Tests/VSGNUFortran/c_code/main.c @@ -0,0 +1,7 @@ +#include <HelloWorldFCMangle.h> // created by FortranCInterface +extern void FC_hello(void); +int main() +{ + FC_hello(); + return 0; +} diff --git a/Tests/VSGNUFortran/runtest.cmake.in b/Tests/VSGNUFortran/runtest.cmake.in new file mode 100644 index 0000000..987207b --- /dev/null +++ b/Tests/VSGNUFortran/runtest.cmake.in @@ -0,0 +1,23 @@ +get_filename_component(MINGW_PATH "@MINGW_GFORTRAN@" PATH) +if(NOT EXISTS "${MINGW_PATH}") + set(test_exe + "@VSGNUFortran_BINARY_DIR@/bin/c_using_fortran@CMAKE_EXECUTABLE_SUFFIX@") + message("run: ${test_exe}") + execute_process(COMMAND "${test_exe}" + RESULT_VARIABLE res) + if(NOT "${res}" EQUAL 0) + message(FATAL_ERROR "${test_exe} returned a non 0 value") + endif() + return() +endif() +file(TO_NATIVE_PATH "${MINGW_PATH}" MINGW_PATH) +string(REPLACE "\\" "\\\\" MINGW_PATH "${MINGW_PATH}") +message("${MINGW_PATH}") +set(test_exe "@VSGNUFortran_BINARY_DIR@/bin/c_using_fortran.exe") +set(ENV{PATH} "${MINGW_PATH}";$ENV{PATH}) +message("run ${test_exe}") +execute_process(COMMAND "${test_exe}" + RESULT_VARIABLE res) +if(NOT "${res}" EQUAL 0) + message(FATAL_ERROR "${test_exe} returned a non 0 value") +endif() diff --git a/Tests/VSGNUFortran/subdir/CMakeLists.txt b/Tests/VSGNUFortran/subdir/CMakeLists.txt new file mode 100644 index 0000000..0b99199 --- /dev/null +++ b/Tests/VSGNUFortran/subdir/CMakeLists.txt @@ -0,0 +1,16 @@ +include(CMakeAddFortranSubdirectory) +# add the fortran subdirectory as a fortran project +# the subdir is fortran, the project is FortranHello +cmake_add_fortran_subdirectory(fortran + PROJECT FortranHello # project name in toplevel CMakeLists.txt + ARCHIVE_DIR ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY} + RUNTIME_DIR bin # ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + LIBRARIES hello world # target libraries created + CMAKE_COMMAND_LINE + -DCMAKE_RUNTIME_OUTPUT_DIRECTORY=${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY=${CMAKE_ARCHIVE_OUTPUT_DIRECTORY} + -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=${CMAKE_LIBRARY_OUTPUT_DIRECTORY} + LINK_LIBRARIES # link interface libraries + LINK_LIBS hello world # hello needs world to link + NO_EXTERNAL_INSTALL + ) diff --git a/Tests/VSGNUFortran/subdir/fortran/CMakeLists.txt b/Tests/VSGNUFortran/subdir/fortran/CMakeLists.txt new file mode 100644 index 0000000..3ee1855 --- /dev/null +++ b/Tests/VSGNUFortran/subdir/fortran/CMakeLists.txt @@ -0,0 +1,46 @@ +cmake_minimum_required(VERSION 2.8) +project(FortranHello Fortran C) + +# add a function to test for -lsunquad on sunpro sun systems. +function(test_sunquad result) + set( TEST_DIR "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/sunq") + file(WRITE "${TEST_DIR}/testsunq.f" " + PROGRAM TEST + END + ") + file(WRITE ${TEST_DIR}/CMakeLists.txt " +project(sunq Fortran) +add_library(sunq SHARED testsunq.f) +target_link_libraries(sunq sunquad) +") + message(STATUS "looking for -lsunquad") + try_compile(RESULT "${TEST_DIR}" "${TEST_DIR}" sunq OUTPUT_VARIABLE OUT) + if("${RESULT}") + message(STATUS "-lsunquad found") + else() + message(STATUS "-lsunquad not found") + endif() + message(STATUS + "looking for sunquad:\nRESULT=[${RESULT}]\nOUTPUT=[\n${OUT}\n]") + set(${result} "${RESULT}" PARENT_SCOPE) +endfunction() + +# check for the fortran c interface mangling +include(FortranCInterface) +FortranCInterface_HEADER(HelloWorldFCMangle.h + MACRO_NAMESPACE "FC_" + SYMBOL_NAMESPACE "FC_" + SYMBOLS hello world) +add_library(hello SHARED hello.f) +add_library(world SHARED world.f) +target_link_libraries(hello world) +if(CMAKE_Fortran_COMPILER_ID MATCHES SunPro) + target_link_libraries(hello fsu) + if(CMAKE_Fortran_PLATFORM_ID MATCHES SunOS) + target_link_libraries(hello sunmath m) + test_sunquad(CMAKE_HAS_SUNQUAD) + if(CMAKE_HAS_SUNQUAD) + target_link_libraries(hello sunquad) + endif() + endif() +endif() diff --git a/Tests/VSGNUFortran/subdir/fortran/hello.f b/Tests/VSGNUFortran/subdir/fortran/hello.f new file mode 100644 index 0000000..e52119a --- /dev/null +++ b/Tests/VSGNUFortran/subdir/fortran/hello.f @@ -0,0 +1,7 @@ +!DEC$ ATTRIBUTES DLLEXPORT :: HELLO + SUBROUTINE HELLO + + PRINT *, 'Hello' + CALL WORLD + + END diff --git a/Tests/VSGNUFortran/subdir/fortran/world.f b/Tests/VSGNUFortran/subdir/fortran/world.f new file mode 100644 index 0000000..0598eee --- /dev/null +++ b/Tests/VSGNUFortran/subdir/fortran/world.f @@ -0,0 +1,6 @@ +!DEC$ ATTRIBUTES DLLEXPORT :: WORLD + SUBROUTINE WORLD + + PRINT *, 'World!' + + END |