]> git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/configure.py
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / seastar / configure.py
1 #!/usr/bin/env python3
2 #
3 # This file is open source software, licensed to you under the terms
4 # of the Apache License, Version 2.0 (the "License"). See the NOTICE file
5 # distributed with this work for additional information regarding copyright
6 # ownership. You may not use this file except in compliance with the License.
7 #
8 # You may obtain a copy of the License at
9 #
10 # http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing,
13 # software distributed under the License is distributed on an
14 # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 # KIND, either express or implied. See the License for the
16 # specific language governing permissions and limitations
17 # under the License.
18 #
19 import argparse
20 import distutils.dir_util
21 import os
22 import seastar_cmake
23 import subprocess
24 import sys
25 import tempfile
26
27 tempfile.tempdir = "./build/tmp"
28
29 def add_tristate(arg_parser, name, dest, help):
30 arg_parser.add_argument('--enable-' + name, dest = dest, action = 'store_true', default = None,
31 help = 'Enable ' + help)
32 arg_parser.add_argument('--disable-' + name, dest = dest, action = 'store_false', default = None,
33 help = 'Disable ' + help)
34
35 def try_compile(compiler, source = '', flags = []):
36 return try_compile_and_link(compiler, source, flags = flags + ['-c'])
37
38 def ensure_tmp_dir_exists():
39 if not os.path.exists(tempfile.tempdir):
40 os.makedirs(tempfile.tempdir)
41
42 def try_compile_and_link(compiler, source = '', flags = []):
43 ensure_tmp_dir_exists()
44 with tempfile.NamedTemporaryFile() as sfile:
45 ofile = tempfile.mktemp()
46 try:
47 sfile.file.write(bytes(source, 'utf-8'))
48 sfile.file.flush()
49 # We can't write to /dev/null, since in some cases (-ftest-coverage) gcc will create an auxiliary
50 # output file based on the name of the output file, and "/dev/null.gcsa" is not a good name
51 return subprocess.call([compiler, '-x', 'c++', '-o', ofile, sfile.name] + flags,
52 stdout = subprocess.DEVNULL,
53 stderr = subprocess.DEVNULL) == 0
54 finally:
55 if os.path.exists(ofile):
56 os.unlink(ofile)
57 def dialect_supported(dialect, compiler='g++'):
58 return try_compile(compiler=compiler, source='', flags=['-std=' + dialect])
59
60 arg_parser = argparse.ArgumentParser('Configure seastar')
61 arg_parser.add_argument('--mode', action='store', choices=seastar_cmake.SUPPORTED_MODES + ['all'], default='all')
62 arg_parser.add_argument('--cflags', action = 'store', dest = 'user_cflags', default = '',
63 help = 'Extra flags for the C++ compiler')
64 arg_parser.add_argument('--ldflags', action = 'store', dest = 'user_ldflags', default = '',
65 help = 'Extra flags for the linker')
66 arg_parser.add_argument('--optflags', action = 'store', dest = 'user_optflags', default = '',
67 help = 'Extra optimization flags for the release mode')
68 arg_parser.add_argument('--api-level', action='store', dest='api_level', default='6',
69 help='Compatibility API level (6=latest)')
70 arg_parser.add_argument('--compiler', action = 'store', dest = 'cxx', default = 'g++',
71 help = 'C++ compiler path')
72 arg_parser.add_argument('--c-compiler', action='store', dest='cc', default='gcc',
73 help = 'C compiler path (for bundled libraries such as dpdk)')
74 arg_parser.add_argument('--c++-dialect', action='store', dest='cpp_dialect', default='',
75 help='C++ dialect to build with [default: %(default)s]')
76 arg_parser.add_argument('--cook', action='append', dest='cook', default=[],
77 help='Supply this dependency locally for development via `cmake-cooking` (can be repeated)')
78 arg_parser.add_argument('--verbose', dest='verbose', action='store_true', help='Make configure output more verbose.')
79 add_tristate(
80 arg_parser,
81 name = 'dpdk',
82 dest = 'dpdk',
83 help = 'DPDK support')
84 add_tristate(
85 arg_parser,
86 name = 'hwloc',
87 dest = 'hwloc',
88 help = 'hwloc support')
89 add_tristate(
90 arg_parser,
91 name = 'alloc-failure-injector',
92 dest = 'alloc_failure_injection',
93 help = 'allocation failure injection')
94 add_tristate(
95 arg_parser,
96 name = 'task-backtrace',
97 dest = 'task_backtrace',
98 help = 'Collect backtrace at deferring points')
99 add_tristate(
100 arg_parser,
101 name = 'unused-result-error',
102 dest = "unused_result_error",
103 help = 'Make [[nodiscard]] violations an error')
104 add_tristate(
105 arg_parser,
106 name = 'debug-shared-ptr',
107 dest = "debug_shared_ptr",
108 help = 'Debug shared_ptr')
109 arg_parser.add_argument('--allocator-page-size', dest='alloc_page_size', type=int, help='override allocator page size')
110 arg_parser.add_argument('--without-tests', dest='exclude_tests', action='store_true', help='Do not build tests by default')
111 arg_parser.add_argument('--without-apps', dest='exclude_apps', action='store_true', help='Do not build applications by default')
112 arg_parser.add_argument('--without-demos', dest='exclude_demos', action='store_true', help='Do not build demonstrations by default')
113 arg_parser.add_argument('--split-dwarf', dest='split_dwarf', action='store_true', default=False,
114 help='use of split dwarf (https://gcc.gnu.org/wiki/DebugFission) to speed up linking')
115 arg_parser.add_argument('--heap-profiling', dest='heap_profiling', action='store_true', default=False, help='Enable heap profiling')
116 arg_parser.add_argument('--prefix', dest='install_prefix', default='/usr/local', help='Root installation path of Seastar files')
117 args = arg_parser.parse_args()
118
119 def identify_best_dialect(dialects, compiler):
120 """Returns the first C++ dialect accepted by the compiler in the sequence,
121 assuming the "best" dialects appear first.
122
123 If no dialects are accepted, the result is the last dialect in the sequence
124 (we assume that this error will be displayed to the user - during compile
125 time - in an informative way).
126
127 """
128 for d in dialects:
129 if dialect_supported(d, compiler):
130 return d
131
132 return d
133
134 if args.cpp_dialect == '':
135 cpp_dialects = ['gnu++17', 'gnu++1z', 'gnu++14', 'gnu++1y']
136 args.cpp_dialect = identify_best_dialect(cpp_dialects, compiler=args.cxx)
137
138 def infer_dpdk_machine(user_cflags):
139 """Infer the DPDK machine identifier (e.g., 'ivb') from the space-separated
140 string of user cflags by scraping the value of `-march` if it is present.
141
142 The default if no architecture is indicated is 'native'.
143 """
144 arch = 'native'
145
146 # `-march` may be repeated, and we want the last one.
147 # strip features, leave only the arch: armv8-a+crc+crypto -> armv8-a
148 for flag in user_cflags.split():
149 if flag.startswith('-march'):
150 arch = flag[7:].split('+')[0]
151
152 MAPPING = {
153 'native': 'native',
154 'nehalem': 'nhm',
155 'westmere': 'wsm',
156 'sandybridge': 'snb',
157 'ivybridge': 'ivb',
158 'armv8-a': 'armv8a',
159 }
160
161 return MAPPING.get(arch, 'native')
162
163 MODES = seastar_cmake.SUPPORTED_MODES if args.mode == 'all' else [args.mode]
164
165 # For convenience.
166 tr = seastar_cmake.translate_arg
167
168 MODE_TO_CMAKE_BUILD_TYPE = {'release' : 'RelWithDebInfo', 'debug' : 'Debug', 'dev' : 'Dev', 'sanitize' : 'Sanitize' }
169
170 def configure_mode(mode):
171 BUILD_PATH = seastar_cmake.BUILD_PATHS[mode]
172
173 CFLAGS = seastar_cmake.convert_strings_to_cmake_list(
174 args.user_cflags,
175 args.user_optflags if seastar_cmake.is_release_mode(mode) else '')
176
177 LDFLAGS = seastar_cmake.convert_strings_to_cmake_list(args.user_ldflags)
178
179 TRANSLATED_ARGS = [
180 '-DCMAKE_BUILD_TYPE={}'.format(MODE_TO_CMAKE_BUILD_TYPE[mode]),
181 '-DCMAKE_C_COMPILER={}'.format(args.cc),
182 '-DCMAKE_CXX_COMPILER={}'.format(args.cxx),
183 '-DCMAKE_INSTALL_PREFIX={}'.format(args.install_prefix),
184 '-DSeastar_API_LEVEL={}'.format(args.api_level),
185 tr(args.exclude_tests, 'EXCLUDE_TESTS_FROM_ALL'),
186 tr(args.exclude_apps, 'EXCLUDE_APPS_FROM_ALL'),
187 tr(args.exclude_demos, 'EXCLUDE_DEMOS_FROM_ALL'),
188 tr(CFLAGS, 'CXX_FLAGS'),
189 tr(LDFLAGS, 'LD_FLAGS'),
190 tr(args.cpp_dialect, 'CXX_DIALECT'),
191 tr(args.dpdk, 'DPDK'),
192 tr(infer_dpdk_machine(args.user_cflags), 'DPDK_MACHINE'),
193 tr(args.hwloc, 'HWLOC', value_when_none='yes'),
194 tr(args.alloc_failure_injection, 'ALLOC_FAILURE_INJECTION', value_when_none='DEFAULT'),
195 tr(args.task_backtrace, 'TASK_BACKTRACE'),
196 tr(args.alloc_page_size, 'ALLOC_PAGE_SIZE'),
197 tr(args.split_dwarf, 'SPLIT_DWARF'),
198 tr(args.heap_profiling, 'HEAP_PROFILING'),
199 tr(args.unused_result_error, 'UNUSED_RESULT_ERROR'),
200 tr(args.debug_shared_ptr, 'DEBUG_SHARED_PTR', value_when_none='default'),
201 ]
202
203 ingredients_to_cook = set(args.cook)
204
205 if args.dpdk:
206 ingredients_to_cook.add('dpdk')
207
208 # Generate a new build by pointing to the source directory.
209 if ingredients_to_cook:
210 # We need to use cmake-cooking for some dependencies.
211 inclusion_arguments = []
212
213 for ingredient in ingredients_to_cook:
214 inclusion_arguments.extend(['-i', ingredient])
215
216 ARGS = seastar_cmake.COOKING_BASIC_ARGS + inclusion_arguments + ['-d', BUILD_PATH, '--']
217 dir = seastar_cmake.ROOT_PATH
218 else:
219 # When building without cooked dependencies, we can invoke cmake directly. We can't call
220 # cooking.sh, because without any -i parameters, it will try to build
221 # everything.
222 ARGS = ['cmake', '-G', 'Ninja', '../..']
223 dir = BUILD_PATH
224 ARGS += TRANSLATED_ARGS
225 if args.verbose:
226 print("Running CMake in '{}' ...".format(dir))
227 print(" \\\n ".join(ARGS))
228 distutils.dir_util.mkpath(BUILD_PATH)
229 subprocess.check_call(ARGS, shell=False, cwd=dir)
230
231 for mode in MODES:
232 configure_mode(mode)