aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJussi Pakkanen <jpakkane@gmail.com>2021-04-06 17:47:16 +0300
committerGitHub <noreply@github.com>2021-04-06 17:47:16 +0300
commitb58e7d84782c08d80692612780806b42af4364e6 (patch)
treed8260f580b981e3a38cc62e46e7ec75e87c2b18f
parent974e49fe0e18dccd479656203f9d9a1b1ec7e6c4 (diff)
parent1dd2bbaa01c4f9b32be2a7d622db9e2e3a549d98 (diff)
downloadmeson-b58e7d84782c08d80692612780806b42af4364e6.zip
meson-b58e7d84782c08d80692612780806b42af4364e6.tar.gz
meson-b58e7d84782c08d80692612780806b42af4364e6.tar.bz2
Merge pull request #8616 from mesonbuild/xcodewarnopt
Set debug, optimization and warning flags in Xcode
-rw-r--r--mesonbuild/backend/xcodebackend.py294
1 files changed, 155 insertions, 139 deletions
diff --git a/mesonbuild/backend/xcodebackend.py b/mesonbuild/backend/xcodebackend.py
index d8876cf..999378f 100644
--- a/mesonbuild/backend/xcodebackend.py
+++ b/mesonbuild/backend/xcodebackend.py
@@ -20,7 +20,7 @@ from .. import mlog
import uuid, os, operator
import typing as T
-from ..mesonlib import MesonException
+from ..mesonlib import MesonException, OptionKey
from ..interpreter import Interpreter
INDENT = '\t'
@@ -42,6 +42,19 @@ XCODETYPEMAP = {'c': 'sourcecode.c.c',
's': 'sourcecode.asm',
'asm': 'sourcecode.asm',
}
+LANGNAMEMAP = {'c': 'C',
+ 'cpp': 'CPLUSPLUS',
+ 'objc': 'OBJC',
+ 'objcpp': 'OBJCPLUSPLUS',
+ }
+OPT2XCODEOPT = {'0': '0',
+ 'g': '0',
+ '1': '1',
+ '2': '2',
+ '3': '3',
+ 's': 's',
+ }
+BOOL2XCODEBOOL = {True: 'YES', False: 'NO'}
class PbxItem:
def __init__(self, value, comment = ''):
@@ -146,6 +159,9 @@ class PbxDict:
ofile.write(indent_level*INDENT + f'{i.key} = ')
i.value.write(ofile, indent_level)
else:
+ print(i)
+ print(i.key)
+ print(i.value)
raise RuntimeError('missing code')
else:
print(i)
@@ -163,11 +179,12 @@ class XCodeBackend(backends.Backend):
super().__init__(build, interpreter)
self.name = 'xcode'
self.project_uid = self.environment.coredata.lang_guids['default'].replace('-', '')[:24]
+ self.buildtype = self.environment.coredata.get_option(OptionKey('buildtype'))
self.project_conflist = self.gen_id()
self.maingroup_id = self.gen_id()
self.all_id = self.gen_id()
self.all_buildconf_id = self.gen_id()
- self.buildtypes = ['debug']
+ self.buildtypes = [self.buildtype]
self.test_id = self.gen_id()
self.test_command_id = self.gen_id()
self.test_buildconf_id = self.gen_id()
@@ -182,7 +199,7 @@ class XCodeBackend(backends.Backend):
return str(uuid.uuid4()).upper().replace('-', '')[:24]
def get_target_dir(self, target):
- dirname = os.path.join(target.get_subdir(), self.environment.coredata.get_option(mesonlib.OptionKey('buildtype')))
+ dirname = os.path.join(target.get_subdir(), self.environment.coredata.get_option(OptionKey('buildtype')))
os.makedirs(os.path.join(self.environment.get_build_dir(), dirname), exist_ok=True)
return dirname
@@ -291,7 +308,7 @@ class XCodeBackend(backends.Backend):
self.buildmap[o] = self.gen_id()
def generate_buildstylemap(self):
- self.buildstylemap = {'debug': self.gen_id()}
+ self.buildstylemap = {self.buildtype: self.gen_id()}
def generate_build_phase_map(self):
for tname, t in self.build.get_build_targets().items():
@@ -306,17 +323,17 @@ class XCodeBackend(backends.Backend):
def generate_build_configuration_map(self):
self.buildconfmap = {}
for t in self.build.get_build_targets():
- bconfs = {'debug': self.gen_id()}
+ bconfs = {self.buildtype: self.gen_id()}
self.buildconfmap[t] = bconfs
def generate_project_configurations_map(self):
- self.project_configurations = {'debug': self.gen_id()}
+ self.project_configurations = {self.buildtype: self.gen_id()}
def generate_buildall_configurations_map(self):
- self.buildall_configurations = {'debug': self.gen_id()}
+ self.buildall_configurations = {self.buildtype: self.gen_id()}
def generate_test_configurations_map(self):
- self.test_configurations = {'debug': self.gen_id()}
+ self.test_configurations = {self.buildtype: self.gen_id()}
def generate_build_configurationlist_map(self):
self.buildconflistmap = {}
@@ -725,9 +742,7 @@ class XCodeBackend(backends.Backend):
settings_dict = PbxDict()
bt_dict.add_item('buildSettings', settings_dict)
settings_dict.add_item('COMBINE_HIDPI_IMAGES', 'YES')
- settings_dict.add_item('GCC_GENERATE_DEBUGGING_SYMBOLS', 'NO')
settings_dict.add_item('GCC_INLINES_ARE_PRIVATE_EXTERN', 'NO')
- settings_dict.add_item('GCC_OPTIMIZATION_LEVEL', 0)
settings_dict.add_item('GCC_PREPROCESSOR_DEFINITIONS', '""')
settings_dict.add_item('GCC_SYMBOLS_PRIVATE_EXTERN', 'NO')
settings_dict.add_item('INSTALL_PATH', '""')
@@ -739,10 +754,8 @@ class XCodeBackend(backends.Backend):
settings_dict.add_item('SYMROOT', '"%s"' % self.environment.get_build_dir())
settings_dict.add_item('USE_HEADERMAP', 'NO')
warn_array = PbxArray()
+ warn_array.add_item('"$(inherited)"')
settings_dict.add_item('WARNING_CFLAGS', warn_array)
- warn_array.add_item('"-Wmost"')
- warn_array.add_item('"-Wno-four-char-constants"')
- warn_array.add_item('"-Wno-unknown-pragmas"')
bt_dict.add_item('name', f'"{buildtype}"')
@@ -754,9 +767,7 @@ class XCodeBackend(backends.Backend):
settings_dict = PbxDict()
bt_dict.add_item('buildSettings', settings_dict)
settings_dict.add_item('COMBINE_HIDPI_IMAGES', 'YES')
- settings_dict.add_item('GCC_GENERATE_DEBUGGING_SYMBOLS', 'NO')
settings_dict.add_item('GCC_INLINES_ARE_PRIVATE_EXTERN', 'NO')
- settings_dict.add_item('GCC_OPTIMIZATION_LEVEL', 0)
settings_dict.add_item('GCC_PREPROCESSOR_DEFINITIONS', '""')
settings_dict.add_item('GCC_SYMBOLS_PRIVATE_EXTERN', 'NO')
settings_dict.add_item('INSTALL_PATH', '""')
@@ -769,127 +780,133 @@ class XCodeBackend(backends.Backend):
settings_dict.add_item('USE_HEADERMAP', 'NO')
warn_array = PbxArray()
settings_dict.add_item('WARNING_CFLAGS', warn_array)
- warn_array.add_item('"-Wmost"')
- warn_array.add_item('"-Wno-four-char-constants"')
- warn_array.add_item('"-Wno-unknown-pragmas"')
+ warn_array.add_item('"$(inherited)"')
bt_dict.add_item('name', f'"{buildtype}"')
# Now finally targets.
- langnamemap = {'c': 'C', 'cpp': 'CPLUSPLUS', 'objc': 'OBJC', 'objcpp': 'OBJCPLUSPLUS'}
for target_name, target in self.build.get_build_targets().items():
- for buildtype in self.buildtypes:
- dep_libs = []
- links_dylib = False
- headerdirs = []
- for d in target.include_dirs:
- for sd in d.incdirs:
- cd = os.path.join(d.curdir, sd)
- headerdirs.append(os.path.join(self.environment.get_source_dir(), cd))
- headerdirs.append(os.path.join(self.environment.get_build_dir(), cd))
- for l in target.link_targets:
- abs_path = os.path.join(self.environment.get_build_dir(),
- l.subdir, buildtype, l.get_filename())
- dep_libs.append("'%s'" % abs_path)
- if isinstance(l, build.SharedLibrary):
- links_dylib = True
- if links_dylib:
- dep_libs = ['-Wl,-search_paths_first', '-Wl,-headerpad_max_install_names'] + dep_libs
- dylib_version = None
- if isinstance(target, build.SharedLibrary):
- ldargs = ['-dynamiclib', '-Wl,-headerpad_max_install_names'] + dep_libs
- install_path = os.path.join(self.environment.get_build_dir(), target.subdir, buildtype)
- dylib_version = target.soversion
- else:
- ldargs = dep_libs
- install_path = ''
- if dylib_version is not None:
- product_name = target.get_basename() + '.' + dylib_version
- else:
- product_name = target.get_basename()
- ldargs += target.link_args
- linker, stdlib_args = self.determine_linker_and_stdlib_args(target)
- ldargs += self.build.get_project_link_args(linker, target.subproject, target.for_machine)
- ldargs += self.build.get_global_link_args(linker, target.for_machine)
- cargs = []
- for dep in target.get_external_deps():
- cargs += dep.get_compile_args()
- ldargs += dep.get_link_args()
- ldstr = ' '.join(ldargs)
- valid = self.buildconfmap[target_name][buildtype]
- langargs = {}
- for lang in self.environment.coredata.compilers[target.for_machine]:
- if lang not in langnamemap:
- continue
- # Add compile args added using add_project_arguments()
- pargs = self.build.projects_args[target.for_machine].get(target.subproject, {}).get(lang, [])
- # Add compile args added using add_global_arguments()
- # These override per-project arguments
- gargs = self.build.global_args[target.for_machine].get(lang, [])
- targs = target.get_extra_args(lang)
- args = pargs + gargs + targs
- if args:
- langname = langnamemap[lang]
- compiler = target.compilers.get(lang)
- lang_cargs = cargs
- if compiler and target.implicit_include_directories:
- lang_cargs += self.get_build_dir_include_args(target, compiler)
- langargs[langname] = args
- langargs[langname] += lang_cargs
- symroot = os.path.join(self.environment.get_build_dir(), target.subdir)
- bt_dict = PbxDict()
- objects_dict.add_item(valid, bt_dict, buildtype)
- bt_dict.add_item('isa', 'XCBuildConfiguration')
- settings_dict = PbxDict()
- bt_dict.add_item('buildSettings', settings_dict)
- settings_dict.add_item('COMBINE_HIDPI_IMAGES', 'YES')
- if dylib_version is not None:
- settings_dict.add_item('DYLIB_CURRENT_VERSION', f'"{dylib_version}')
- settings_dict.add_item('EXECUTABLE_PREFIX', f'"{target.prefix}"')
- if target.suffix == '':
- suffix = ''
- else:
- suffix = '.' + target.suffix
- settings_dict.add_item('EXECUTABLE_SUFFIX', f'"{suffix}"')
- settings_dict.add_item('GCC_GENERATE_DEBUGGING_SYMBOLS', 'YES')
- settings_dict.add_item('GCC_INLINES_ARE_PRIVATE_EXTERN', 'NO')
- settings_dict.add_item('GCC_OPTIMIZATION_LEVEL', 0)
- if target.has_pch:
- # Xcode uses GCC_PREFIX_HEADER which only allows one file per target/executable. Precompiling various header files and
- # applying a particular pch to each source file will require custom scripts (as a build phase) and build flags per each
- # file. Since Xcode itself already discourages precompiled headers in favor of modules we don't try much harder here.
- pchs = target.get_pch('c') + target.get_pch('cpp') + target.get_pch('objc') + target.get_pch('objcpp')
- # Make sure to use headers (other backends require implementation files like *.c *.cpp, etc; these should not be used here)
- pchs = [pch for pch in pchs if pch.endswith('.h') or pch.endswith('.hh') or pch.endswith('hpp')]
- if pchs:
- if len(pchs) > 1:
- mlog.warning('Unsupported Xcode configuration: More than 1 precompiled header found "{}". Target "{}" might not compile correctly.'.format(str(pchs), target.name))
- relative_pch_path = os.path.join(target.get_subdir(), pchs[0]) # Path relative to target so it can be used with "$(PROJECT_DIR)"
- settings_dict.add_item('GCC_PRECOMPILE_PREFIX_HEADER', 'YES')
- settings_dict.add_item('GCC_PREFIX_HEADER', f'"$(PROJECT_DIR)/{relative_pch_path}"')
- settings_dict.add_item('GCC_PREPROCESSOR_DEFINITIONS', '""')
- settings_dict.add_item('GCC_SYMBOLS_PRIVATE_EXTERN', 'NO')
- if headerdirs:
- quotedh = ','.join(['"\\"%s\\""' % i for i in headerdirs])
- settings_dict.add_item('HEADER_SEARCH_PATHS', f'({quotedh}')
- settings_dict.add_item('INSTALL_PATH', f'"{install_path}"')
- settings_dict.add_item('LIBRARY_SEARCH_PATHS', '""')
- if isinstance(target, build.SharedLibrary):
- settings_dict.add_item('LIBRARY_STYLE', 'DYNAMIC')
- for langname, args in langargs.items():
- settings_dict.add_item(f'OTHER_{langname}FLAGS', args)
- settings_dict.add_item('OTHER_LDFLAGS', f'"{ldstr}"')
- settings_dict.add_item('OTHER_REZFLAGS', '""')
- settings_dict.add_item('PRODUCT_NAME', product_name)
- settings_dict.add_item('SECTORDER_FLAGS', '""')
- settings_dict.add_item('SYMROOT', f'"{symroot}"')
- settings_dict.add_item('SYSTEM_HEADER_SEARCH_PATHS', '"{}"'.format(self.environment.get_build_dir()))
- settings_dict.add_item('USE_HEADERMAP', 'NO')
- warn_array = PbxArray()
- settings_dict.add_item('WARNING_CFLAGS', warn_array)
- warn_array.add_item('"-Wmost"')
- warn_array.add_item('"-Wno-four-char-constants"')
- warn_array.add_item('"-Wno-unknown-pragmas"')
- bt_dict.add_item('name', buildtype)
+ self.generate_single_build_target(objects_dict, target_name, target)
+
+
+ def generate_single_build_target(self, objects_dict, target_name, target):
+ for buildtype in self.buildtypes:
+ dep_libs = []
+ links_dylib = False
+ headerdirs = []
+ for d in target.include_dirs:
+ for sd in d.incdirs:
+ cd = os.path.join(d.curdir, sd)
+ headerdirs.append(os.path.join(self.environment.get_source_dir(), cd))
+ headerdirs.append(os.path.join(self.environment.get_build_dir(), cd))
+ for l in target.link_targets:
+ abs_path = os.path.join(self.environment.get_build_dir(),
+ l.subdir, buildtype, l.get_filename())
+ dep_libs.append("'%s'" % abs_path)
+ if isinstance(l, build.SharedLibrary):
+ links_dylib = True
+ if links_dylib:
+ dep_libs = ['-Wl,-search_paths_first', '-Wl,-headerpad_max_install_names'] + dep_libs
+ dylib_version = None
+ if isinstance(target, build.SharedLibrary):
+ ldargs = ['-dynamiclib', '-Wl,-headerpad_max_install_names'] + dep_libs
+ install_path = os.path.join(self.environment.get_build_dir(), target.subdir, buildtype)
+ dylib_version = target.soversion
+ else:
+ ldargs = dep_libs
+ install_path = ''
+ if dylib_version is not None:
+ product_name = target.get_basename() + '.' + dylib_version
+ else:
+ product_name = target.get_basename()
+ ldargs += target.link_args
+ linker, stdlib_args = self.determine_linker_and_stdlib_args(target)
+ ldargs += self.build.get_project_link_args(linker, target.subproject, target.for_machine)
+ ldargs += self.build.get_global_link_args(linker, target.for_machine)
+ cargs = []
+ for dep in target.get_external_deps():
+ cargs += dep.get_compile_args()
+ ldargs += dep.get_link_args()
+ ldstr = ' '.join(ldargs)
+ valid = self.buildconfmap[target_name][buildtype]
+ langargs = {}
+ for lang in self.environment.coredata.compilers[target.for_machine]:
+ if lang not in LANGNAMEMAP:
+ continue
+ compiler = target.compilers.get(lang)
+ # Start with warning args
+ warn_args = compiler.get_warn_args(self.get_option_for_target(OptionKey('warning_level'), target))
+ # Add compile args added using add_project_arguments()
+ pargs = self.build.projects_args[target.for_machine].get(target.subproject, {}).get(lang, [])
+ # Add compile args added using add_global_arguments()
+ # These override per-project arguments
+ gargs = self.build.global_args[target.for_machine].get(lang, [])
+ targs = target.get_extra_args(lang)
+ args = warn_args + pargs + gargs + targs
+ if args:
+ langname = LANGNAMEMAP[lang]
+ lang_cargs = cargs
+ if compiler and target.implicit_include_directories:
+ lang_cargs += self.get_build_dir_include_args(target, compiler)
+ langargs[langname] = args
+ langargs[langname] += lang_cargs
+ symroot = os.path.join(self.environment.get_build_dir(), target.subdir)
+ bt_dict = PbxDict()
+ objects_dict.add_item(valid, bt_dict, buildtype)
+ bt_dict.add_item('isa', 'XCBuildConfiguration')
+ settings_dict = PbxDict()
+ bt_dict.add_item('buildSettings', settings_dict)
+ settings_dict.add_item('COMBINE_HIDPI_IMAGES', 'YES')
+ if dylib_version is not None:
+ settings_dict.add_item('DYLIB_CURRENT_VERSION', f'"{dylib_version}')
+ settings_dict.add_item('EXECUTABLE_PREFIX', f'"{target.prefix}"')
+ if target.suffix == '':
+ suffix = ''
+ else:
+ suffix = '.' + target.suffix
+ settings_dict.add_item('EXECUTABLE_SUFFIX', f'"{suffix}"')
+ settings_dict.add_item('GCC_GENERATE_DEBUGGING_SYMBOLS', BOOL2XCODEBOOL[self.get_option_for_target(OptionKey('debug'), target)])
+ settings_dict.add_item('GCC_INLINES_ARE_PRIVATE_EXTERN', 'NO')
+ settings_dict.add_item('GCC_OPTIMIZATION_LEVEL', OPT2XCODEOPT[self.get_option_for_target(OptionKey('optimization'), target)])
+ if target.has_pch:
+ # Xcode uses GCC_PREFIX_HEADER which only allows one file per target/executable. Precompiling various header files and
+ # applying a particular pch to each source file will require custom scripts (as a build phase) and build flags per each
+ # file. Since Xcode itself already discourages precompiled headers in favor of modules we don't try much harder here.
+ pchs = target.get_pch('c') + target.get_pch('cpp') + target.get_pch('objc') + target.get_pch('objcpp')
+ # Make sure to use headers (other backends require implementation files like *.c *.cpp, etc; these should not be used here)
+ pchs = [pch for pch in pchs if pch.endswith('.h') or pch.endswith('.hh') or pch.endswith('hpp')]
+ if pchs:
+ if len(pchs) > 1:
+ mlog.warning('Unsupported Xcode configuration: More than 1 precompiled header found "{}". Target "{}" might not compile correctly.'.format(str(pchs), target.name))
+ relative_pch_path = os.path.join(target.get_subdir(), pchs[0]) # Path relative to target so it can be used with "$(PROJECT_DIR)"
+ settings_dict.add_item('GCC_PRECOMPILE_PREFIX_HEADER', 'YES')
+ settings_dict.add_item('GCC_PREFIX_HEADER', f'"$(PROJECT_DIR)/{relative_pch_path}"')
+ settings_dict.add_item('GCC_PREPROCESSOR_DEFINITIONS', '""')
+ settings_dict.add_item('GCC_SYMBOLS_PRIVATE_EXTERN', 'NO')
+ if headerdirs:
+ quotedh = ','.join(['"\\"%s\\""' % i for i in headerdirs])
+ settings_dict.add_item('HEADER_SEARCH_PATHS', f'({quotedh}')
+ settings_dict.add_item('INSTALL_PATH', f'"{install_path}"')
+ settings_dict.add_item('LIBRARY_SEARCH_PATHS', '""')
+ if isinstance(target, build.SharedLibrary):
+ settings_dict.add_item('LIBRARY_STYLE', 'DYNAMIC')
+ self.add_otterargs(settings_dict, langargs)
+ settings_dict.add_item('OTHER_LDFLAGS', f'"{ldstr}"')
+ settings_dict.add_item('OTHER_REZFLAGS', '""')
+ settings_dict.add_item('PRODUCT_NAME', product_name)
+ settings_dict.add_item('SECTORDER_FLAGS', '""')
+ settings_dict.add_item('SYMROOT', f'"{symroot}"')
+ settings_dict.add_item('SYSTEM_HEADER_SEARCH_PATHS', '"{}"'.format(self.environment.get_build_dir()))
+ settings_dict.add_item('USE_HEADERMAP', 'NO')
+ warn_array = PbxArray()
+ settings_dict.add_item('WARNING_CFLAGS', warn_array)
+ warn_array.add_item('"$(inherited)"')
+ bt_dict.add_item('name', buildtype)
+
+ def add_otterargs(self, settings_dict, langargs):
+ for langname, args in langargs.items():
+ if args:
+ # FIXME, proper quoting
+ settings_dict.add_item(f'OTHER_{langname}FLAGS', '"' + ' '.join(args) + '"')
def generate_xc_configurationList(self, objects_dict):
# FIXME: sort items
@@ -901,7 +918,7 @@ class XCodeBackend(backends.Backend):
for buildtype in self.buildtypes:
confs_arr.add_item(self.project_configurations[buildtype], buildtype)
conf_dict.add_item('defaultConfigurationIsVisible', 0)
- conf_dict.add_item('defaultConfigurationName', 'debug')
+ conf_dict.add_item('defaultConfigurationName', self.buildtype)
# Now the all target
all_dict = PbxDict()
@@ -912,7 +929,7 @@ class XCodeBackend(backends.Backend):
for buildtype in self.buildtypes:
conf_arr.add_item(self.buildall_configurations[buildtype], buildtype)
all_dict.add_item('defaultConfigurationIsVisible', 0)
- all_dict.add_item('defaultConfigurationName', 'debug')
+ all_dict.add_item('defaultConfigurationName', self.buildtype)
# Test target
test_dict = PbxDict()
@@ -923,7 +940,7 @@ class XCodeBackend(backends.Backend):
for buildtype in self.buildtypes:
conf_arr.add_item(self.test_configurations[buildtype], buildtype)
test_dict.add_item('defaultConfigurationIsVisible', 0)
- test_dict.add_item('defaultConfigurationName', 'debug')
+ test_dict.add_item('defaultConfigurationName', self.buildtype)
for target_name in self.build.get_build_targets():
t_dict = PbxDict()
@@ -932,11 +949,10 @@ class XCodeBackend(backends.Backend):
t_dict.add_item('isa', 'XCConfigurationList')
conf_arr = PbxArray()
t_dict.add_item('buildConfigurations', conf_arr)
- typestr = 'debug'
- idval = self.buildconfmap[target_name][typestr]
- conf_arr.add_item(idval, typestr)
+ idval = self.buildconfmap[target_name][self.buildtype]
+ conf_arr.add_item(idval, self.buildtype)
t_dict.add_item('defaultConfigurationIsVisible', 0)
- t_dict.add_item('defaultConfigurationName', typestr)
+ t_dict.add_item('defaultConfigurationName', self.buildtype)
def generate_prefix(self, pbxdict):