Commit 5f091356 authored by Jason Rhinelander's avatar Jason Rhinelander

Added setup.py infrastructure && make install

parent 5e16942e
......@@ -4,41 +4,27 @@ project(pyeris CXX)
include(GNUInstallDirs)
set(pyeris_author "Jason Rhinelander <jason@imaginary.ca>")
set(pyeris_author_name "Jason Rhinelander")
set(pyeris_author_email "jason@imaginary.ca")
set(pyeris_author "${pyeris_author_name} <${pyeris_author_email}>")
set(pyeris_url "https://git.imaginary.ca/eris/pyeris")
set(pyeris_description "Agent-based economic modelling library - python interface")
# pyeris package version
set(PYERIS_VERSION_MAJOR "0")
set(PYERIS_VERSION_MINOR "0")
set(PYERIS_VERSION_PATCH "0")
set(PYERIS_VERSION_PATCH "1")
set(PYERIS_VERSION "${PYERIS_VERSION_MAJOR}.${PYERIS_VERSION_MINOR}.${PYERIS_VERSION_PATCH}")
# pyeris library version (CURRENT.REVISION.AGE), which is totally separate
# from the above. See http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
# Basic rules for updating these when releasing a new pyeris version:
# - If the new release has an API change:
# - CURRENT gets updated
# - REVISION gets set to 0
# - If the API change was purely an addition, increment AGE
# - Otherwise (i.e. an API change or removal), reset AGE to 0
# - Otherwise, if the release has no API change but has code changes:
# - REVISION gets incremented
# - (CURRENT and AGE stay the same)
# If there is no code change (e.g. the release is just a documentation update)
# then none of these change.
#
# (So something like 3.7.1 indicates the 8th revision of the libpyeris.so.3
# interface, and that code that links against libpyeris.so.2 can safely link
# against this version, but code that links against libpyeris.so.1 cannot.
set(LIBPYERIS_CURRENT "0")
set(LIBPYERIS_REVISION "0")
set(LIBPYERIS_AGE "0")
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules)
set(ERIS_VERSION_REQUIRED "0.5.0")
# Set this to try recent (3.x) versions first; otherwise on Debian/Ubuntu the
# python2.7 version gets picked up by default instead.
set(Python_ADDITIONAL_VERSIONS 3.3 3.4 3.5 3.6 3.7)
find_package(PythonInterp REQUIRED)
# No in-source building
include(MacroEnsureOutOfSourceBuild)
macro_ensure_out_of_source_build("${PROJECT_NAME} requires an out-of-source build. Create a build directory and run 'cmake ${CMAKE_SOURCE_DIR} [options]'.")
......@@ -66,53 +52,6 @@ include_directories(${EIGEN3_INCLUDE_DIR})
#find_package(PythonLibs REQUIRED)
#include_directories(${PYTHON_INCLUDE_DIRS})
#set(BOOST_MIN 1.46.0)
#find_package(Boost ${BOOST_MIN} REQUIRED)
# The boost python library can live under a few different names: on Debian/Ubuntu, it seems to be
# named libboost_python-pyXY.so where XY are the major/minor python version (e.g. 35 for 3.5.z).
# Some distributions instead name it libboost_pythonX.so, where X is the major version. The code
# below tries the following, where $V is the major and $v is the minor version, and uses the first one found:
# libboost_python-py$V.$v.so
# libboost_python-$V.$v.so
# libboost_python$V.$v.so
# libboost_python-py$V$v.so
# libboost_python-$V$v.so
# libboost_python$V$v.so
# libboost_python-py$V.so
# libboost_python-$V.so
# libboost_python$V.so
# libboost_python.so
# If none are found, we give up.
#string(REGEX MATCH "^[0-9]+" boost_py_v "${PYTHONLIBS_VERSION_STRING}")
#string(REGEX MATCH "^[0-9]+\\.[0-9]+" boost_py_vdotmin "${PYTHONLIBS_VERSION_STRING}")
#string(REGEX REPLACE "\\." "" boost_py_vmin "${boost_py_vdotmin}")
#if ("${boost_py_v}" STREQUAL "" OR "${boost_py_vdotmin}" STREQUAL "" OR "${boost_py_vmin}" STREQUAL "")
# message(FATAL "Could not determine python library major/minor version: ${PYTHONLIBS_VERSION_STRING}")
#endif()
#foreach (v "${boost_py_vdotmin}" "${boost_py_vmin}" "${boost_py_v}")
# foreach (suffix "-py" "-" "")
# string(TOUPPER "${suffix}${v}" suffv_uc)
# message(STATUS "Checking for boost_python${suffix}${v}")
# find_package(Boost ${BOOST_MIN} COMPONENTS "python${suffix}${v}")
# set(Boost_PYTHON_FOUND ${Boost_PYTHON${suffv_uc}_FOUND})
# if (Boost_PYTHON_FOUND)
# break()
# endif()
# endforeach()
# if (Boost_PYTHON_FOUND)
# break()
# endif()
#endforeach()
#
## Lastly look for libboost_python.so: make this REQUIRED so that it fails if not found
#if (NOT Boost_PYTHON_FOUND)
# message(STATUS "Checking for boost_python")
# find_package(Boost ${BOOST_MIN} REQUIRED COMPONENTS python)
#endif()
#
#include_directories(${Boost_INCLUDE_DIRS})
#link_directories(${Boost_LIBRARY_DIRS})
find_package(PkgConfig REQUIRED)
pkg_check_modules(ERIS REQUIRED liberis)
if(ERIS_VERSION VERSION_LESS "${ERIS_VERSION_REQUIRED}")
......@@ -123,22 +62,58 @@ link_directories(${ERIS_LIBRARY_DIRS})
add_definitions(${ERIS_CFLAGS_OTHER})
file(GLOB core_src RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} pyeris/core.cpp pyeris/core/*.cpp)
file(GLOB pos_src RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} pyeris/position.cpp pyeris/position/*.cpp)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/package/eris DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/eris)
pybind11_add_module(core ${core_src})
target_link_libraries(core ${ERIS_LIBRARIES})
set_target_properties(core PROPERTIES OUTPUT_NAME eris/core)
pybind11_add_module(position ${pos_src})
target_link_libraries(position ${ERIS_LIBRARIES})
set_target_properties(position PROPERTIES OUTPUT_NAME eris/position)
set(pyeris_modules "")
# Add a pyeris.module. The module is built from the pyeris/${name}.cpp and pyeris/name/*.cpp files.
function(add_pyeris_module name)
file(GLOB src RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} pyeris/${name}.cpp pyeris/${name}/*.cpp)
pybind11_add_module(${name} ${src})
target_link_libraries(${name} ${ERIS_LIBRARIES})
list(APPEND pyeris_modules ${name})
set(pyeris_modules "${pyeris_modules}" PARENT_SCOPE)
endfunction()
add_pyeris_module(core)
add_pyeris_module(position)
# We configure setup.py twice: the first during cmake configuration, which handles things like the version,
# then again when building, which handles the python_libloc substitution. Set the substitution value to
# itself here, to allow the re-substitution later:
set(python_libloc "@python_libloc@")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in ${CMAKE_CURRENT_BINARY_DIR}/partial-setup.py.in @ONLY)
set(python_libloc "")
foreach(module ${pyeris_modules})
set(python_libloc "${python_libloc}'eris.${module}': '$<TARGET_FILE:${module}>', ")
endforeach()
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/setup.py"
COMMAND ${CMAKE_COMMAND}
-D SUBST_SOURCE=${CMAKE_CURRENT_BINARY_DIR}/partial-setup.py.in
-D SUBST_DEST=${CMAKE_CURRENT_BINARY_DIR}/setup.py
-D python_libloc=${python_libloc}
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/subst-final.cmake
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/partial-setup.py.in"
VERBATIM)
#-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/gen-setup.py.cmake
# echo "${python_libloc}")
set(BUILD_TIMESTAMP "${CMAKE_CURRENT_BINARY_DIR}/build/setup.py-build-timestamp")
add_custom_command(OUTPUT "${BUILD_TIMESTAMP}"
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/setup.py build
COMMAND ${CMAKE_COMMAND} -E touch ${BUILD_TIMESTAMP}
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/setup.py"
core position)
add_custom_target(python-build ALL DEPENDS ${BUILD_TIMESTAMP})
install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/setup.py install)")
# Make libpyeris.pc for the 'make install' target
#configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libpyeris.pc.in
......
if (NOT SUBST_SOURCE)
message(FATAL_ERROR "Must set -D SUBST_SOURCE=source_file")
endif()
if (NOT SUBST_DEST)
message(FATAL_ERROR "Must set -D SUBST_DEST=dest_file")
endif()
configure_file("${SUBST_SOURCE}" "${SUBST_DEST}" @ONLY)
from distutils.core import setup
from distutils.extension import Extension
from distutils.command.build_ext import build_ext
from os import path
from shutil import copy2
with open(path.join('@CMAKE_SOURCE_DIR@', 'README.md'), encoding='utf-8' ) as f:
long_description = f.read()
liblocs = {@python_libloc@}
# cmake builds the .so files in eris already; all we need to do is move them to the right place
class FakeBuild(build_ext):
def run(self):
for ext in self.extensions:
copy2(liblocs[ext.name], self.get_ext_fullpath(ext.name))
setup(
name = 'pyeris',
version = '@PYERIS_VERSION_MAJOR@.@PYERIS_VERSION_MINOR@.@PYERIS_VERSION_PATCH@',
description = '@pyeris_description@',
long_description = long_description,
url = '@pyeris_url@',
author = '@pyeris_author_name@',
author_email = '@pyeris_author_email@',
license = 'GPLv3+',
classifiers = [
'Development Status :: 3 - Alpha',
'Intended Audience :: Developers',
'Intended Audience :: Science/Research',
'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
'Programming Language :: C++',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 3'
],
keywords = 'eris economics ABM agent-based modelling',
packages = ['eris'],
ext_modules=[Extension('eris.'+x, []) for x in '@pyeris_modules@'.split(';')],
cmdclass = { 'build_ext': FakeBuild },
package_dir = { '': '@CMAKE_CURRENT_BINARY_DIR@' },
)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment