Cross compiling now actually works

At least for non-PyQt based extensions
This commit is contained in:
Kovid Goyal 2023-01-27 12:47:46 +05:30
parent d13404d9ea
commit ef9e669ef9
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 44 additions and 47 deletions

View File

@ -69,32 +69,10 @@ class Extension:
self.libraries = d['libraries'] = kwargs.get('libraries', []) self.libraries = d['libraries'] = kwargs.get('libraries', [])
self.cflags = d['cflags'] = kwargs.get('cflags', []) self.cflags = d['cflags'] = kwargs.get('cflags', [])
self.uses_icu = 'icuuc' in self.libraries self.uses_icu = 'icuuc' in self.libraries
if self.needs_cxx and kwargs.get('needs_c++'):
std_prefix = '/std:' if iswindows else '-std='
self.cflags.insert(0, std_prefix + 'c++' + kwargs['needs_c++'])
if iswindows:
self.cflags.append('/DCALIBRE_MODINIT_FUNC=PyMODINIT_FUNC')
else:
return_type = 'PyObject*'
extern_decl = 'extern "C"' if self.needs_cxx else ''
self.cflags.append(
'-DCALIBRE_MODINIT_FUNC='
'{} __attribute__ ((visibility ("default"))) {}'.format(extern_decl, return_type))
if kwargs.get('needs_c'):
self.cflags.insert(0, '-std=c' + kwargs['needs_c'])
self.ldflags = d['ldflags'] = kwargs.get('ldflags', []) self.ldflags = d['ldflags'] = kwargs.get('ldflags', [])
self.optional = d['options'] = kwargs.get('optional', False) self.optional = d['options'] = kwargs.get('optional', False)
of = kwargs.get('optimize_level', None) self.needs_cxx_std = kwargs.get('needs_c++')
if of is None: self.needs_c_std = kwargs.get('needs_c')
of = '/Ox' if iswindows else '-O3'
else:
flag = '/O%d' if iswindows else '-O%d'
of = flag % of
self.cflags.insert(0, of)
self.only_build_for = kwargs.get('only', '') self.only_build_for = kwargs.get('only', '')
@ -245,6 +223,7 @@ class Environment(NamedTuple):
cc_output_flag: str cc_output_flag: str
platform_name: str platform_name: str
dest_ext: str dest_ext: str
std_prefix: str
def inc_dirs_to_cflags(self, dirs) -> List[str]: def inc_dirs_to_cflags(self, dirs) -> List[str]:
return [self.external_inc_prefix+x for x in dirs] return [self.external_inc_prefix+x for x in dirs]
@ -264,6 +243,7 @@ def init_env(debug=False, sanitize=False, compiling_for='native'):
libdir_prefix = '-L' libdir_prefix = '-L'
lib_prefix = '-l' lib_prefix = '-l'
lib_suffix = '' lib_suffix = ''
std_prefix = '-std='
obj_suffix = '.o' obj_suffix = '.o'
cc_input_c_flag = cc_input_cpp_flag = '-c' cc_input_c_flag = cc_input_cpp_flag = '-c'
cc_output_flag = '-o' cc_output_flag = '-o'
@ -321,17 +301,18 @@ def init_env(debug=False, sanitize=False, compiling_for='native'):
if iswindows or compiling_for == 'windows': if iswindows or compiling_for == 'windows':
platform_name = 'windows' platform_name = 'windows'
std_prefix = '/std:'
cc = cxx = win_cc cc = cxx = win_cc
linker = win_ld linker = win_ld
cflags, ldflags = basic_windows_flags(debug) cflags, ldflags = basic_windows_flags(debug)
if compiling_for == 'windows': if compiling_for == 'windows':
cc = 'clang-cl' cc = cxx = 'clang-cl'
linker = 'lld-link' linker = 'lld-link'
splat = '.build-cache/xwin/splat' splat = '.build-cache/xwin/splat'
for I in 'sdk/include/um sdk/include/cppwinrt sdk/include/shared sdk/include/ucrt crt/include': for I in 'sdk/include/um sdk/include/cppwinrt sdk/include/shared sdk/include/ucrt crt/include'.split():
cflags.append('/external:I') cflags.append('/external:I')
cflags.append(f'{splat}/{I}') cflags.append(f'{splat}/{I}')
for L in './sdk/lib/um/x86_64 crt/lib/x86_64': for L in 'sdk/lib/um/x86_64 crt/lib/x86_64 sdk/lib/ucrt/x86_64'.split():
ldflags.append(f'/libpath:{splat}/{L}') ldflags.append(f'/libpath:{splat}/{L}')
else: else:
for p in win_inc: for p in win_inc:
@ -359,7 +340,7 @@ def init_env(debug=False, sanitize=False, compiling_for='native'):
cflags.extend('-I' + x for x in get_python_include_paths()) cflags.extend('-I' + x for x in get_python_include_paths())
ldflags.append('/LIBPATH:'+os.path.join(sysconfig.get_config_var('prefix'), 'libs')) ldflags.append('/LIBPATH:'+os.path.join(sysconfig.get_config_var('prefix'), 'libs'))
return Environment( return Environment(
platform_name=platform_name, dest_ext=dest_ext, platform_name=platform_name, dest_ext=dest_ext, std_prefix=std_prefix,
cc=cc, cxx=cxx, cflags=cflags, ldflags=ldflags, linker=linker, make=NMAKE if iswindows else 'make', lib_prefix=lib_prefix, cc=cc, cxx=cxx, cflags=cflags, ldflags=ldflags, linker=linker, make=NMAKE if iswindows else 'make', lib_prefix=lib_prefix,
obj_suffix=obj_suffix, cc_input_c_flag=cc_input_c_flag, cc_input_cpp_flag=cc_input_cpp_flag, cc_output_flag=cc_output_flag, obj_suffix=obj_suffix, cc_input_c_flag=cc_input_c_flag, cc_input_cpp_flag=cc_input_cpp_flag, cc_output_flag=cc_output_flag,
internal_inc_prefix=internal_inc_prefix, external_inc_prefix=external_inc_prefix, libdir_prefix=libdir_prefix, lib_suffix=lib_suffix) internal_inc_prefix=internal_inc_prefix, external_inc_prefix=external_inc_prefix, libdir_prefix=libdir_prefix, lib_suffix=lib_suffix)
@ -410,9 +391,18 @@ class Build(Command):
def dump_db(self, name, db): def dump_db(self, name, db):
os.makedirs('build', exist_ok=True) os.makedirs('build', exist_ok=True)
existing = []
try:
with open(f'build/{name}_commands.json', 'rb') as f:
existing = json.load(f)
except FileNotFoundError:
pass
combined = {x['output']: x for x in existing}
for x in db:
combined[x['output']] = x
try: try:
with open(f'build/{name}_commands.json', 'w') as f: with open(f'build/{name}_commands.json', 'w') as f:
json.dump(db, f, indent=2) json.dump(tuple(combined.values()), f, indent=2)
except OSError as err: except OSError as err:
if err.errno != errno.EROFS: if err.errno != errno.EROFS:
raise raise
@ -525,7 +515,23 @@ class Build(Command):
else: else:
oinc = [env.cc_output_flag, obj] oinc = [env.cc_output_flag, obj]
einc = env.inc_dirs_to_cflags(ext.inc_dirs) einc = env.inc_dirs_to_cflags(ext.inc_dirs)
cmd = [compiler] + env.cflags + ext.cflags + einc + sinc + oinc if env.cc_output_flag.startswith('/'):
cflags = ['/DCALIBRE_MODINIT_FUNC=PyMODINIT_FUNC']
else:
return_type = 'PyObject*'
extern_decl = 'extern "C"' if ext.needs_cxx else ''
cflags = [
'-DCALIBRE_MODINIT_FUNC='
'{} __attribute__ ((visibility ("default"))) {}'.format(extern_decl, return_type)]
if ext.needs_cxx and ext.needs_cxx_std:
cflags.append(env.std_prefix + 'c++' + ext.needs_cxx_std)
if ext.needs_c_std and not env.std_prefix.startswith('/'):
cflags.append(env.std_prefix + 'c' + ext.needs_c_std)
if env is self.windows_cross_env:
cflags.append('-Wno-deprecated-experimental-coroutine')
cmd = [compiler] + env.cflags + cflags + ext.cflags + einc + sinc + oinc
return CompileCommand(cmd, src, obj) return CompileCommand(cmd, src, obj)
objects = [] objects = []
@ -538,11 +544,10 @@ class Build(Command):
if self.newer(cc.dest, [src]+ext.headers): if self.newer(cc.dest, [src]+ext.headers):
ans.append(cc) ans.append(cc)
env = self.env_for_compilation_db(ext) env = self.env_for_compilation_db(ext)
if env is None: if env is not None:
continue db.append({
db.append({ 'arguments': get(src, env).cmd, 'directory': os.getcwd(), 'file': os.path.relpath(src, os.getcwd()),
'arguments': get(src, env).cmd, 'directory': os.getcwd(), 'file': os.path.relpath(src, os.getcwd()), 'output': os.path.relpath(cc.dest, os.getcwd())})
'output': os.path.relpath(cc.dest, os.getcwd())})
return ans, objects return ans, objects
def get_link_command(self, ext, objects, lddb): def get_link_command(self, ext, objects, lddb):
@ -550,7 +555,7 @@ class Build(Command):
def get(env: Environment) -> LinkCommand: def get(env: Environment) -> LinkCommand:
dest = self.dest(ext, env) dest = self.dest(ext, env)
compiler = env.cxx if ext.needs_cxx else env.cc compiler = env.cxx if ext.needs_cxx else env.cc
linker = self.env.linker or compiler linker = env.linker or compiler
cmd = [linker] cmd = [linker]
elib = env.lib_dirs_to_ldflags(ext.lib_dirs) elib = env.lib_dirs_to_ldflags(ext.lib_dirs)
xlib = env.libraries_to_ldflags(ext.libraries) xlib = env.libraries_to_ldflags(ext.libraries)
@ -559,10 +564,10 @@ class Build(Command):
if ext.uses_icu: if ext.uses_icu:
# windows has its own ICU libs that dont work # windows has its own ICU libs that dont work
pre_ld_flags = elib pre_ld_flags = elib
cmd += pre_ld_flags + self.env.ldflags + ext.ldflags + elib + xlib + \ cmd += pre_ld_flags + env.ldflags + ext.ldflags + elib + xlib + \
['/EXPORT:' + init_symbol_name(ext.name)] + objects + ext.extra_objs + ['/OUT:'+dest] ['/EXPORT:' + init_symbol_name(ext.name)] + objects + ext.extra_objs + ['/OUT:'+dest]
else: else:
cmd += objects + ext.extra_objs + ['-o', dest] + self.env.ldflags + ext.ldflags + elib + xlib cmd += objects + ext.extra_objs + ['-o', dest] + env.ldflags + ext.ldflags + elib + xlib
return LinkCommand(cmd, objects, dest) return LinkCommand(cmd, objects, dest)
env = self.env_for_compilation_db(ext) env = self.env_for_compilation_db(ext)

View File

@ -191,7 +191,7 @@
"sources": "calibre/utils/windows/winspeech.cpp", "sources": "calibre/utils/windows/winspeech.cpp",
"libraries": "WindowsApp", "libraries": "WindowsApp",
"needs_c++": "20", "needs_c++": "20",
"cflags": "/X /Zc:__cplusplus /bigobj /await /permissive- /WX /Zc:twoPhase-" "cflags": "/X /Zc:__cplusplus /bigobj /permissive- /WX /Zc:twoPhase-"
}, },
{ {
"name": "wpd", "name": "wpd",

View File

@ -66,14 +66,6 @@ enum {
EXIT_REQUESTED EXIT_REQUESTED
}; };
// trim from start (in place)
static inline void
ltrim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
return !std::isspace(ch);
}));
}
// trim from end (in place) // trim from end (in place)
static inline void static inline void
rtrim(std::string &s) { rtrim(std::string &s) {