-
Notifications
You must be signed in to change notification settings - Fork 2
/
cmake_build.py
126 lines (111 loc) · 5.58 KB
/
cmake_build.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#!/usr/bin/env python3
# Below are reasons why `setup.py` was replaced with PEP 517, 518, compatible build system:
# 1. The setuptools project has stopped maintaining all direct invocations of setup.py years ago, and distutils is
# deprecated. There are undoubtedly many ways that your setup.py-based system is broken today, even if it's not failing
# loudly or obviously.
# 2. Direct invocations of setup.py cannot bootstrap their own dependencies, and so some CLI is necessary for dependency
# management
# 3. The setuptools project no longer wants to provide any public CLI, and will be actively removing the existing
# interface (though the time scale for this is long).
# 4. PEP 517, 518 and other standards-based packaging are the future of the Python ecosystem and a lot of progress has
# been made on making this upgrade seamless.
# This script builds pressiodemoapps library with use of cmake as a subprocess.
# Script can take command line arguments to setup OpenMP(--openmp, True when given, False when not given) default OFF
# and BuildMode (--build_mode=Release or --build_mode=Debug) default Release
# Script creates directory in main project directory (<PROJECT_DIR>/build/pressiodemoapps) where library is build and
# where __init__.py file is copied. Based on that pressiodemoapps package is created later with build.
import os
import sys
try:
project_path = f"{os.sep}".join(os.path.abspath(__file__).split(os.sep)[:-1])
sys.path.append(project_path)
print(f"Project path was added to sys.path: {project_path}")
except Exception as e:
print(f"Can not add project path to system path! Exiting!\nERROR: {e}")
exit(1)
import argparse
import platform
import shutil
import subprocess
class CMakeBuild:
""" Class responsible fo building library for pressiodemoapps. """
def __init__(self, build_mode: str = 'Release', enable_omp: bool = False, build_args: list = None):
# Options
self.build_mode = build_mode
self.enable_omp = enable_omp
# Directories
self.build_dir = os.path.join(project_path, 'build')
self._check_and_create_dir(directory=self.build_dir)
self.temp_dir = os.path.join(self.build_dir, 'temp')
self._check_and_create_dir(directory=self.temp_dir)
self.library = os.path.join(self.build_dir, 'pressiodemoapps')
self._check_and_create_dir(directory=self.library)
# Build args
if build_args is not None:
self.build_args = build_args
else:
self.build_args = list()
self._copy_init_file_to_package()
self._cli()
self._print_info()
def _cli(self):
""" Support for common line arguments. """
parser = argparse.ArgumentParser()
parser.add_argument("--openmp", action="store_true", help="Enables OpenMP if given")
parser.add_argument("--build_mode", help="Defines build mode: Release or Debug")
args = parser.parse_args()
if args.openmp:
self.enable_omp = True
if args.openmp == 'Debug':
self.build_mode = 'Debug'
else:
self.build_mode = 'Release'
@staticmethod
def _check_and_create_dir(directory: str):
""" Checks if directory exists. If it does not, creates the path recursively"""
if not os.path.exists(directory):
os.makedirs(directory)
def _copy_init_file_to_package(self):
""" Copy init file to the library directory """
file_src = os.path.join(project_path, 'pressiodemoapps', '__init__.py')
file_dst = os.path.join(self.library, '__init__.py')
shutil.copyfile(file_src, file_dst)
def _print_info(self):
""" Prints information regarding paths and options. """
print('\n')
print('======> PROJECT DIRECTORIES <======')
print(f'===> Project path: {project_path}')
print(f'===> Build directory: {self.build_dir}')
print(f'===> Temp directory: {self.temp_dir}')
print(f'===> Library directory: {self.library}')
print('\n')
print('======> PROJECT OPTIONS <======')
print(f'===> Project build mode: {self.build_mode}')
print(f'===> Enable OpenMP: {self.enable_omp}')
print('\n')
def _check_os_env_vars(self):
""" Checks environment variables. """
if "CXX" not in os.environ:
if platform.system() != 'Windows':
compiler = subprocess.run(['which', 'g++'], capture_output=True)
if compiler.returncode == 1:
print(f"CXX env var missing, needs to point to your target C++ compiler")
exit(1)
else:
cxx = compiler.stdout.decode('utf-8').replace('\n', '')
os.environ["CXX"] = cxx
else:
print(f"CXX env var missing, needs to point to your target C++ compiler")
exit(1)
if "CMAKE_BUILD_PARALLEL_LEVEL" not in os.environ:
self.build_args.append('-j4')
def build(self):
""" Builds library with Cmake. """
self._check_os_env_vars()
cmake_args = [f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={self.library}", f"-DPYTHON_EXECUTABLE={sys.executable}",
f"-DCMAKE_BUILD_TYPE={self.build_mode}", "-DPRESSIODEMOAPPS_ENABLE_BINDINGS=On",
"-DCMAKE_VERBOSE_MAKEFILE=On", f"-DPRESSIODEMOAPPS_ENABLE_OPENMP={self.enable_omp}"]
subprocess.check_call(["cmake", project_path] + cmake_args, cwd=self.temp_dir)
subprocess.check_call(["cmake", "--build", "."] + self.build_args, cwd=self.temp_dir)
if __name__ == '__main__':
CMakeBuild().build()