Prune change-management.rst and update links.
[alexxy/gromacs.git] / python_packaging / sample_restraint / CMakeLists.txt
1 cmake_minimum_required(VERSION 3.9.6)
2 # If you are using this repository as a template, you should probably change the
3 # project name and adopt your own versioning scheme.
4 project(sample_restraint VERSION 0.0.8)
5
6 find_package(PythonInterp)
7
8 # Check if Python package is being built directly or via add_subdirectory.
9 # I.e. is this being built as a standalone project or as part of the GROMACS
10 # build tree (for testing)?
11 set(GMXAPI_EXTENSION_MASTER_PROJECT OFF)
12 if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
13     set(GMXAPI_EXTENSION_MASTER_PROJECT ON)
14 endif()
15
16 # TODO: (Issue #3027) Handle pybind sources both for forked projects and
17 #  for GROMACS-project-internal testing.
18 # Projects based on this subtree should bundle pybind11 sources.
19 # The GROMACS project already bundles one copy of pybind sources for the gmxapi
20 # Python package, and should package them with source distribution archives of
21 # the paackage that should be installed with GROMACS, but the pybind sources
22 # would only be available to this project with some additional management by
23 # the parent project CMake configuration.
24 # Also reference https://gitlab.com/gromacs/gromacs/-/issues/2896
25 if(GMXAPI_EXTENSION_MASTER_PROJECT)
26     # TODO: (Issue #3027) Handle locally available sources.
27     set(GMXAPI_EXTENSION_USE_BUNDLED_PYBIND OFF CACHE BOOL
28         "Use pybind11 headers bundled with this repository. If OFF, CMake does `find_package(pybind11)`.")
29     if(GMXAPI_EXTENSION_USE_BUNDLED_PYBIND)
30         add_subdirectory(external/pybind)
31     else()
32         option(GMXAPI_EXTENSION_DOWNLOAD_PYBIND ON)
33         if(GMXAPI_EXTENSION_DOWNLOAD_PYBIND)
34             configure_file(CMakeLists.pybind.in pybind-download/CMakeLists.txt)
35             execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
36                             RESULT_VARIABLE result
37                             WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/pybind-download)
38             if(result)
39                 message(FATAL_ERROR "CMake step for pybind download failed: ${result}")
40             endif()
41             execute_process(COMMAND ${CMAKE_COMMAND} --build .
42                             RESULT_VARIABLE result
43                             WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/pybind-download)
44             if(result)
45                 message(FATAL_ERROR "Build step for pybind failed: ${result}")
46             endif()
47             add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/pybind-src)
48         else()
49             find_package(pybind11 2.2 REQUIRED)
50         endif()
51     endif()
52 else()
53     # If configuring as part of the GROMACS project, pybind11 2.2 has already been found.
54 endif()
55
56
57 # This project requires a GROMACS supporting gmxapi 0.0.8 or higher. It should
58 # be sufficient to source the GMXRC, but you can also set the GROMACS_DIR or
59 # gmxapi_DIR environment variable to help CMake find the GROMACS installation.
60
61 # Note that the code will need to be built separately for different versions of Python and for substantially different
62 # versions of GROMACS. If building from the command line, you can specify a Python executable with the PYTHON_EXECUTABLE
63 # variable. For instance, to make sure you are building for your default Python, cmake -DPYTHON_EXECUTABLE=`which python`.
64
65 set(CMAKE_CXX_STANDARD 14)
66 set(CMAKE_CXX_VISIBILITY_PRESET hidden)
67
68 # CMake modules are in a subdirectory to keep this file cleaner
69 list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
70
71 # Assuming GROMACS is in our path or that we have set either the gmxapi_DIR or GROMACS_DIR environment variables,
72 # this will find the CMake configuration for the GROMACS libraries we need and define the CMake library objects
73 # Gromacs::gmxapi
74 if(GMXAPI_EXTENSION_MASTER_PROJECT)
75     find_package(gmxapi
76                  0.0.8 REQUIRED CONFIG
77                  PATHS "$ENV{GROMACS_DIR}"
78                  )
79
80     message(STATUS "Found gmxapi version ${gmxapi_VERSION_MAJOR}.${gmxapi_VERSION_MINOR}.${gmxapi_VERSION_PATCH}")
81 endif()
82
83 if(GMXAPI_EXTENSION_MASTER_PROJECT)
84     ######################################################
85     # The following is boiler-plate recommended by GROMACS
86     ######################################################
87     # In principle, this could be deduced from GROMACS_IS_DOUBLE returned by
88     # find_package(GROMACS) based on the suffix alone, but it is clearer that the
89     # user explicitly sets what they want to get, and then need to provide a suffix
90     # to match.
91     option(GMX_DOUBLE "Use double precision" OFF)
92     set(GMX_SUFFIX "" CACHE STRING "Suffix for the GROMACS installation to use (empty for default)")
93
94     # This does not allow for a non-suffixed double-precision libgromacs, but
95     # that should be rare enough for demonstration purposes.
96     if (GMX_DOUBLE AND NOT GMX_SUFFIX)
97         set(GROMACS_SUFFIX "_d")
98     else()
99         set(GROMACS_SUFFIX ${GMX_SUFFIX})
100     endif()
101
102     find_package(GROMACS REQUIRED)
103     gromacs_check_double(GMX_DOUBLE)
104     gromacs_check_compiler(CXX)
105     include_directories(${GROMACS_INCLUDE_DIRS})
106     add_definitions(${GROMACS_DEFINITIONS})
107
108     # Use static linking on MSVC
109     if (CMAKE_GENERATOR MATCHES "Visual Studio")
110         string(REPLACE /MD /MT CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE})
111         set(CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE} CACHE STRING "" FORCE)
112         string(REPLACE /MD /MT CMAKE_C_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG})
113         set(CMAKE_C_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG} CACHE STRING "" FORCE)
114     endif()
115
116     # Activate the CTest module for this directory.
117     include(CTest)
118 endif()
119
120 ########################################################
121
122 # Stuff for our plugin:
123 #
124 # If the user is not in a virtual environment and is not a privileged user and has not specified an install location
125 # for the Python module (GMXPLUGIN_INSTALL_PATH), this option causes the automatic install location to query the user
126 # site-packages directory instead of using the default site-packages directory for the interpreter.
127 option(GMXPLUGIN_USER_INSTALL
128        "Override the default site-packages directory with the user-specific Python packages directory. \
129        (Do not use with virtual environments.) \
130        Has no effect if GMXPLUGIN_INSTALL_PATH is defined or cached. \
131        Use -UGMXPLUGIN_INSTALL_PATH to force recalculation."
132        OFF)
133
134 # Since a user may have multiple virtual environments with different Python interpreters, it is generally confusing to
135 # have a package for a virtual environment installed in the user's default user site-packages directory. If virtual
136 # environments are in use at all, we recommend you do _not_ perform a "user" install in or out of a virtual env. If you do
137 # not use any Python virtual environments, we recommend you _do_ perform "user" installs exclusively. Overall, we
138 # we recommend you use Python virtual environments and activate one before performing a regular (non-"user") install.
139
140 if (PYTHONINTERP_FOUND)
141     message(STATUS "Found Python interpreter: ${PYTHON_EXECUTABLE}")
142     if (PYTHON_LIBRARIES)
143         if (GMXPLUGIN_USER_INSTALL)
144             execute_process(COMMAND ${PYTHON_EXECUTABLE} "-m" "site" "--user-site"
145                             OUTPUT_VARIABLE GMXPLUGIN_DEFAULT_SITE_PACKAGES
146                             OUTPUT_STRIP_TRAILING_WHITESPACE)
147             message(STATUS "Python user site-packages directory is ${GMXPLUGIN_DEFAULT_SITE_PACKAGES}")
148         else()
149             execute_process(COMMAND ${PYTHON_EXECUTABLE} -c
150                                 "import sys; import os; \
151                                 print(os.path.abspath(os.path.join(sys.prefix, \
152                                     'lib', \
153                                     'python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}', \
154                                     'site-packages')))"
155                             OUTPUT_VARIABLE GMXPLUGIN_DEFAULT_SITE_PACKAGES
156                             OUTPUT_STRIP_TRAILING_WHITESPACE)
157             message(STATUS "Python site-packages directory is ${GMXPLUGIN_DEFAULT_SITE_PACKAGES}")
158         endif()
159     else()
160         message(FATAL_ERROR
161             "Found Python interpreter ${PYTHON_EXECUTABLE} but this Python installation does not have developer tools."
162             "Set PYTHON_EXECUTABLE to the Python interpreter that was installed with a working Python.h header file.")
163     endif()
164 else()
165     message(FATAL_ERROR "Could not find Python interpreter. Set CMake flag -DPYTHON_EXECUTABLE=/path/to/python to hint.")
166 endif()
167
168 # At some point this may be part of a CMake package with several components for which a single CMAKE_INSTALL_PREFIX does
169 # not make sense, so let's manage the install path separately.
170 set(GMXPLUGIN_INSTALL_PATH ${GMXPLUGIN_DEFAULT_SITE_PACKAGES} CACHE PATH
171     "Path to Python module install location (site-packages). For an automatically determined install location based on \
172     the Python installation, leave undefined or explicitly undefined with -UGMXPLUGIN_INSTALL_PATH and, optionally, set \
173     GMXPLUGIN_USER_INSTALL on or off to specify the installation's site-packages directory or the 'user' site-packages \
174     directory.")
175
176 if(GMXAPI_EXTENSION_MASTER_PROJECT)
177     message(STATUS "Python module will be installed to GMXPLUGIN_INSTALL_PATH cache value ${GMXPLUGIN_INSTALL_PATH}")
178 endif()
179
180 # TODO: (Issue #3027) Handle Googletest sources both for forked projects and
181 #  for GROMACS-project-internal testing.
182 # Projects based on this subtree should bundle googletest sources.
183 # The GROMACS project already bundles googletest sources for internal use, but
184 # they will only be available to this project with some additional management by
185 # the parent project CMake configuration.
186 option(DOWNLOAD_GOOGLETEST "Download the latest master branch of googletest." OFF)
187 mark_as_advanced(DOWNLOAD_GOOGLETEST)
188
189 # Prevent overriding the parent project's compiler/linker
190 # settings on Windows
191 set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
192
193
194 # Now move on to building the custom code.
195 add_subdirectory(src)
196
197 # Set up documentation build targets (work in progress).
198 add_subdirectory(docs)
199
200 # Process CMake configuration for Python and C++ tests.
201 include(CTest)
202 if(BUILD_TESTING)
203     include(GoogleTest)
204     add_subdirectory(tests)
205 endif()