Skip to content

Commit

Permalink
Merge pull request #261 from sandialabs/update_setuppy
Browse files Browse the repository at this point in the history
Refactor setup.py and add test() to pycompadre
  • Loading branch information
kuberry authored Nov 8, 2021
2 parents 79fcb18 + 4b8557b commit 052e79a
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 51 deletions.
24 changes: 12 additions & 12 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ else() # Raw CMake Project
SET(CMAKE_SKIP_BUILD_RPATH FALSE)
SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
SET(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_LIBDIR} ${CMAKE_INSTALL_RPATH})
SET(CMAKE_INSTALL_RPATH "../${CMAKE_INSTALL_LIBDIR}")

# RPATH should always include the folder it is called from
bob_option(PYTHON_CALLING_BUILD "Python setuptools calling build" OFF)
Expand All @@ -96,17 +96,17 @@ else() # Raw CMake Project
OUTPUT_STRIP_TRAILING_WHITESPACE )
ENDIF()
MESSAGE(STATUS "PYTHON_EXECUTABLE: ${PYTHON_EXECUTABLE}")
if (APPLE)
SET(CMAKE_BUILD_RPATH ${CMAKE_BUILD_RPATH} "@loader_path/")
SET(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH} "@loader_path/")
if (NOT(PYTHON_CALLING_BUILD))
# If python is calling the build, it will provide these flags
SET(CMAKE_PYTHON_SHARED_LINKER_FLAGS "-undefined dynamic_lookup -nodefaultlibs")
# change RPATH for a flat directory structure
# when installing pycompadre as Python package
if (PYTHON_CALLING_BUILD)
if (APPLE)
SET(CMAKE_BUILD_RPATH ${CMAKE_BUILD_RPATH} "@loader_path/")
SET(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH} "@loader_path/")
else()
SET(CMAKE_BUILD_RPATH ${CMAKE_BUILD_RPATH} "$ORIGIN/")
SET(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH} "$ORIGIN/")
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,origin")
endif()
else()
SET(CMAKE_BUILD_RPATH ${CMAKE_BUILD_RPATH} "$ORIGIN/")
SET(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH} "$ORIGIN/")
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,origin")
endif()
endif()

Expand Down Expand Up @@ -420,6 +420,7 @@ set(Compadre_KEY_BOOLS
Compadre_USE_CUDA
Compadre_USE_MPI
Compadre_USE_PYTHON
PYTHON_CALLING_BUILD
)

set(Compadre_KEY_INTS
Expand All @@ -433,7 +434,6 @@ set(Compadre_KEY_STRINGS
Compadre_COMMIT
Compadre_CXX_FLAGS
Compadre_CMAKE_ARGS
GMLS_Module_DEST
Compadre_INSTALL_PREFIX
)

Expand Down
2 changes: 1 addition & 1 deletion cmake/Compadre_Version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.4.0
1.4.1
10 changes: 6 additions & 4 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
include_tribits_build()

# ERROR MESSAGES IF A TEST IS NOT RUN
SET(OPENBLAS_NUM_THREADS "1")


###############
#
#
Expand Down Expand Up @@ -193,6 +189,8 @@ if (Compadre_EXAMPLES)

# WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} )
if (Compadre_USE_PYTHON)
FILE(COPY "${CMAKE_CURRENT_SOURCE_DIR}/../pycompadre/examples/test_pycompadre.py" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/../pycompadre/examples")
FILE(COPY "${CMAKE_CURRENT_SOURCE_DIR}/../pycompadre/examples/test_pycompadre_manifold.py" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/../pycompadre/examples")
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/Python_3D_Convergence.py.in" "${CMAKE_CURRENT_BINARY_DIR}/Python_3D_Convergence.py" @ONLY)
ADD_TEST(NAME GMLS_Python_Convergence_Test_3d_Point_Reconstruction COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_BINARY_DIR}/Python_3D_Convergence.py" "--kokkos-threads=4")
SET_TESTS_PROPERTIES(GMLS_Python_Convergence_Test_3d_Point_Reconstruction PROPERTIES LABELS "IntegrationTest;integration;python;kokkos" TIMEOUT 10)
Expand All @@ -201,6 +199,10 @@ if (Compadre_EXAMPLES)
ADD_TEST(NAME GMLS_Matlab_Python_Interface_1d_Point_Reconstruction COMMAND "matlab" "-nodisplay" "-nojvm" "-nosplash" "-nodesktop" "-r \"try, run('${SWIG_PREFIX}/Matlab_1D_Using_Python_Interface.m'), catch, exit(1), end, exit(0);\"")
SET_TESTS_PROPERTIES(GMLS_Matlab_Python_Interface_1d_Point_Reconstruction PROPERTIES LABELS "IntegrationTest;integration;python;kokkos;matlab" TIMEOUT 10)
endif()

ADD_TEST(NAME PyCOMPADRE_Tests COMMAND "${PYTHON_EXECUTABLE}" "-c" "import sys;sys.path.insert(0,'${PYTHON_LIBRARY_PREFIX}');import pycompadre;pycompadre.test();")
SET_TESTS_PROPERTIES(PyCOMPADRE_Tests PROPERTIES LABELS "pycompadre" TIMEOUT 10)

endif()

endif (Compadre_TESTS)
Expand Down
2 changes: 1 addition & 1 deletion examples/Python_3D_Convergence.py.in
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import sys

# installation folder
gmls_python_installation_path = "@PYTHON_LIBRARY_PREFIX@"
sys.path.append(gmls_python_installation_path)
sys.path.insert(0,gmls_python_installation_path)

import pycompadre

Expand Down
3 changes: 2 additions & 1 deletion pycompadre/examples/test_pycompadre.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import math
import random
import pycompadre
import sys

kokkos_obj=pycompadre.KokkosParser()
kokkos_obj=pycompadre.KokkosParser(sys.argv)

# function used to generate sample data
def exact(coord,order,dimension):
Expand Down
3 changes: 2 additions & 1 deletion pycompadre/examples/test_pycompadre_manifold.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from unittest import TestCase
import pycompadre
import numpy as np
import sys

# initialize Kokkos
kp = pycompadre.KokkosParser()
kp = pycompadre.KokkosParser(sys.argv)

# get GMLS approximate at all x_pred, as well as reconstruction about attempt_center_about_coord
def approximate(input_dimensions, porder, wpower, wtype, epsilon_multiplier, attempt_center_about_coord):
Expand Down
42 changes: 42 additions & 0 deletions pycompadre/pycompadre.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,48 @@ Implementation details at:

m.def("Wab", &GMLS::Wab, py::arg("r"), py::arg("h"), py::arg("weighting type"), py::arg("p"), py::arg("n"), "Evaluate weighting kernel.");

m.def("test", [] {
py::module_ nose;
try {
nose = py::module_::import("nose");
} catch (...) {
std::cerr << "test() requires nose module." << std::endl;
}

py::module_ pathlib;
try {
pathlib = py::module::import("pathlib");
} catch (...) {
std::cerr << "test() requires pathlib module." << std::endl;
}

std::string examples_path;
try {
py::object this_pycompadre = py::module::import("pycompadre");
auto location = this_pycompadre.attr("__file__").cast<std::string>();
py::object path = pathlib.attr("Path")(location);
#ifdef PYTHON_CALLING_BUILD
examples_path = py::str(path.attr("parent")).cast<std::string>() + "/examples";
#else
examples_path = py::str(path.attr("parent")).cast<std::string>() + "/pycompadre/examples";
#endif
} catch (...) {
std::cerr << "Error getting examples path from pycompadre module." << std::endl;
}

bool result = false;
try {
printf("Running examples in: %s\n", examples_path.c_str());
std::vector<std::string> argv = {"--where", examples_path, "-v"};
using namespace pybind11::literals;
result = nose.attr("run")("argv"_a=argv).cast<bool>();
} catch (...) {
std::cerr << "Error running nosetests." << std::endl;
}
return result;
}
);

#ifdef COMPADRE_VERSION_MAJOR
m.attr("__version__") = std::to_string(COMPADRE_VERSION_MAJOR) + "." + std::to_string(COMPADRE_VERSION_MINOR) + "." + std::to_string(COMPADRE_VERSION_PATCH);
#else
Expand Down
118 changes: 87 additions & 31 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,18 +80,32 @@
import sys
import platform
import subprocess
import distutils
from pkg_resources import parse_version

from setuptools import setup, Extension
from setuptools import setup, Extension, Command
from setuptools.command.build_ext import build_ext
from distutils.version import LooseVersion
from setuptools.command.install import install

class CMakeExtension(Extension):
def __init__(self, name, sourcedir=''):
Extension.__init__(self, name, sources=[])
self.sourcedir = os.path.abspath(sourcedir)

# Overload Command for SetupTest to prevent build_ext being called again
class SetupTest(Command):
'''
Tests the installed pycompadre module
'''
user_options=list()
def initialize_options(self): pass
def finalize_options(self): pass
def run(self):
try:
import pycompadre
except:
print('Install pycompadre before running test')
pycompadre.test()

class CMakeBuild(build_ext):
def run(self):
try:
Expand All @@ -101,7 +115,7 @@ def run(self):
", ".join(e.name for e in self.extensions))

if platform.system() == "Windows":
cmake_version = LooseVersion(re.search(r'version\s*([\d.]+)', out.decode()).group(1))
cmake_version = parse_version(re.search(r'version\s*([\d.]+)', out.decode()).group(1))
if cmake_version < '3.1.0':
raise RuntimeError("CMake >= 3.1.0 is required on Windows")

Expand All @@ -115,48 +129,88 @@ def build_extension(self, ext):
if not extdir.endswith(os.path.sep):
extdir += os.path.sep

# Parse string for kokkos architecture

cmake_config = os.getenv("CMAKE_CONFIG_FILE")
if cmake_config:
print("Custom cmake args file set to: %s"%(cmake_config,))
if os.path.exists(cmake_config):
print("Custom cmake args file set to: %s"%(cmake_config,))
else:
assert False, "CMAKE_CONFIG_FILE specified, but does not exist."
else:
cmake_config = ""
print("Custom cmake args file not set.")

#cmake_file_string = ""
#try:
# if cmake_file != None:
# cmake_file_string = str(cmake_file)
# print("Custom cmake args file set to: %s"%(cmake_file_string,))
# else:
# print("Custom cmake args file not set.")
#except:
# print("Custom cmake args file not set.")
# look for cmake_opts.txt and use it if found
if os.path.exists(ext.sourcedir+"/cmake_opts.txt"):
cmake_config = ext.sourcedir+"/cmake_opts.txt"
print("CMAKE_CONFIG_FILE not set, but cmake_opts.txt FOUND, so using: %s"%(cmake_config,))
else:
cmake_config = ""
print("Custom cmake args file not set.")

# Configure CMake
#config = 'Debug' if self.debug else 'Release'
cmake_args = ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + extdir,
'-DCMAKE_CXX_FLAGS= -O3 ',
'-DPYTHON_EXECUTABLE=' + sys.executable,
'-DGMLS_Module_DEST=' + extdir,
'-DCMAKE_INSTALL_PREFIX=' + extdir,
'-DCMAKE_OSX_DEPLOYMENT_TARGET=10.9',
'-DCompadre_USE_PYTHON:BOOL=ON',
'-DCompadre_USE_MATLAB:BOOL=ON',
'-DCompadre_EXAMPLES:BOOL=OFF',
'-DPYTHON_CALLING_BUILD:BOOL=ON',]

cmake_file_list = list()
#if (cmake_file_string != ""):
if (cmake_config != ""):
#cmake_arg_list = [line.rstrip('\n') for line in open(cmake_file_string)]
cmake_arg_list = [line.rstrip('\n') for line in open(cmake_config)]
for arg in cmake_arg_list:
cmake_args.append('-D'+arg)
print('Custom CMake Args: ', cmake_arg_list)

cfg = 'Debug' if self.debug else 'Release'
# turn off examples and tests unless specified in a file
tests_in_cmake_args = False
for arg in cmake_args:
if 'Compadre_TESTS' in arg:
tests_in_cmake_args = True
break
if not tests_in_cmake_args:
cmake_args += ['-DCompadre_TESTS:BOOL=OFF']
examples_in_cmake_args = False
for arg in cmake_args:
if 'Compadre_EXAMPLES' in arg:
examples_in_cmake_args = True
break
if not examples_in_cmake_args:
cmake_args += ['-DCompadre_EXAMPLES:BOOL=OFF']

# add level 3 optimization if not specified in a file
flag_in_cmake_args = False
for arg in cmake_args:
if 'CMAKE_CXX_FLAGS' in arg:
flag_in_cmake_args = True
break
if not flag_in_cmake_args:
cmake_args += ['-DCMAKE_CXX_FLAGS= -O3 -g ']

# add level 3 optimization if not specified in a file
build_type_in_cmake_args = False
for arg in cmake_args:
if 'CMAKE_BUILD_TYPE' in arg:
build_type_in_cmake_args = True
break

# allow 'python setup.py build_ext --debug install' to have precedence over CMAKE_BUILD_TYPE
if self.debug and not build_type_in_cmake_args:
cfg = 'Debug'
cmake_args += ['-DCMAKE_BUILD_TYPE=Debug']
elif not self.debug and not build_type_in_cmake_args:
cfg = 'None'
cmake_args += ['-DCMAKE_BUILD_TYPE=None']
elif not self.debug: # was specified in file only
for arg in cmake_args[:]:
if 'CMAKE_BUILD_TYPE' in arg:
# break down and copy to cfg
cfg = arg.split('=')[1]
break
else: # was specified in file and --debug in command
# delete specified from cmake_args
for arg in cmake_args[:]:
if 'CMAKE_BUILD_TYPE' in arg:
cmake_args.remove(arg)
cmake_args += ['-DCMAKE_BUILD_TYPE=Debug']
cfg = 'Debug'

build_args = ['--config', cfg]

if platform.system() == "Windows":
Expand All @@ -165,15 +219,16 @@ def build_extension(self, ext):
cmake_args += ['-A', 'x64']
build_args += ['--', '/m']
else:
cmake_args += ['-DCMAKE_BUILD_TYPE=' + cfg]
build_args += ['--', '-j2']

env = os.environ.copy()
env['CXXFLAGS'] = '{} -DVERSION_INFO=\\"{}\\"'.format(env.get('CXXFLAGS', ''),
self.distribution.get_version())
if not os.path.exists(self.build_temp):
os.makedirs(self.build_temp)
print("CMake Args:", cmake_args)
subprocess.check_call(['cmake', ext.sourcedir] + cmake_args, cwd=self.build_temp, env=env)
print("Build Args:", build_args)
subprocess.check_call(['cmake', '--build', '.'] + build_args, cwd=self.build_temp)

with open("README.md", "r") as fh:
Expand All @@ -200,9 +255,10 @@ def build_extension(self, ext):
ext_modules=[CMakeExtension('pycompadre'),],
cmdclass={
'build_ext': CMakeBuild,
'test': SetupTest,
},
tests_require=['nose','numpy'],
test_suite='nose.collector',
data_files=[('examples', ['pycompadre/examples/test_pycompadre.py',
'pycompadre/examples/test_pycompadre_manifold.py']),],
include_package_data=True,
zip_safe=False,
)

0 comments on commit 052e79a

Please sign in to comment.