| #!/usr/bin/env python3 |
| |
| # Copyright 2017 Jussi Pakkanen |
| |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| import sys, os, subprocess, shutil |
| |
| import argparse |
| |
| def add_arguments(parser: 'argparse.ArgumentParser') -> None: |
| parser.add_argument('--debarch', default=None, |
| help='The dpkg architecture to generate.') |
| parser.add_argument('--gccsuffix', default="", |
| help='A particular gcc version suffix if necessary.') |
| parser.add_argument('-o', required=True, dest='outfile', |
| help='The output file.') |
| |
| #parser = argparse.ArgumentParser(description='''Generate cross compilation definition file for the Meson build system. |
| # |
| #If you do not specify the --arch argument, Meson assumes that running |
| #plain 'dpkg-architecture' will return correct information for the |
| #host system. |
| # |
| #This script must be run in an environment where CPPFLAGS et al are set to the |
| #same values used in the actual compilation. |
| #''' |
| #) |
| |
| def locate_path(program): |
| if os.path.isabs(program): |
| return program |
| for d in os.get_exec_path(): |
| f = os.path.join(d, program) |
| if os.access(f, os.X_OK): |
| return f |
| raise ValueError("%s not found on $PATH" % program) |
| |
| def write_args_line(ofile, name, args): |
| if len(args) == 0: |
| return |
| ostr = name + ' = [' |
| ostr += ', '.join("'" + i + "'" for i in args) |
| ostr += ']\n' |
| ofile.write(ostr) |
| |
| def write_args_from_envvars(ofile): |
| import shlex |
| cppflags = shlex.split(os.environ.get('CPPFLAGS', '')) |
| cflags = shlex.split(os.environ.get('CFLAGS', '')) |
| cxxflags = shlex.split(os.environ.get('CXXFLAGS', '')) |
| ldflags = shlex.split(os.environ.get('LDFLAGS', '')) |
| |
| c_args = cppflags + cflags |
| cpp_args = cppflags + cxxflags |
| c_link_args = cflags + ldflags |
| cpp_link_args = cxxflags + ldflags |
| |
| write_args_line(ofile, 'c_args', c_args) |
| write_args_line(ofile, 'cpp_args', cpp_args) |
| write_args_line(ofile, 'c_link_args', c_link_args) |
| write_args_line(ofile, 'cpp_link_args', cpp_link_args) |
| |
| cpu_family_map = dict(mips64el="mips64", |
| i686='x86') |
| cpu_map = dict(armhf="arm7hlf", |
| mips64el="mips64",) |
| |
| class CrossInfo: |
| def __init__(self): |
| self.compilers = {} |
| self.binaries = {} |
| self.properties = {} |
| |
| self.system = None |
| self.cpu = None |
| self.cpu_family = None |
| self.endian = None |
| |
| def deb_compiler_lookup(infos, compilerstems, host_arch, gccsuffix): |
| for langname, stem in compilerstems: |
| compilername = f'{host_arch}-{stem}{gccsuffix}' |
| try: |
| p = locate_path(compilername) |
| infos.compilers[langname] = p |
| except ValueError: |
| pass |
| |
| def detect_debianlike(options): |
| if options.debarch is None: |
| cmd = ['dpkg-architecture'] |
| else: |
| cmd = ['dpkg-architecture', '-a' + options.debarch] |
| output = subprocess.check_output(cmd, universal_newlines=True, |
| stderr=subprocess.DEVNULL) |
| data = {} |
| for line in output.split('\n'): |
| line = line.strip() |
| if line == '': |
| continue |
| k, v = line.split('=', 1) |
| data[k] = v |
| host_arch = data['DEB_HOST_GNU_TYPE'] |
| host_os = data['DEB_HOST_ARCH_OS'] |
| host_cpu_family = cpu_family_map.get(data['DEB_HOST_GNU_CPU'], |
| data['DEB_HOST_GNU_CPU']) |
| host_cpu = cpu_map.get(data['DEB_HOST_ARCH'], |
| data['DEB_HOST_ARCH']) |
| host_endian = data['DEB_HOST_ARCH_ENDIAN'] |
| |
| compilerstems = [('c', 'gcc'), |
| ('cpp', 'h++'), |
| ('objc', 'gobjc'), |
| ('objcpp', 'gobjc++')] |
| infos = CrossInfo() |
| deb_compiler_lookup(infos, compilerstems, host_arch, options.gccsuffix) |
| if len(infos.compilers) == 0: |
| print('Warning: no compilers were detected.') |
| infos.binaries['ar'] = locate_path("%s-ar" % host_arch) |
| infos.binaries['strip'] = locate_path("%s-strip" % host_arch) |
| infos.binaries['objcopy'] = locate_path("%s-objcopy" % host_arch) |
| infos.binaries['ld'] = locate_path("%s-ld" % host_arch) |
| try: |
| infos.binaries['pkgconfig'] = locate_path("%s-pkg-config" % host_arch) |
| except ValueError: |
| pass # pkg-config is optional |
| try: |
| infos.binaries['cups-config'] = locate_path("cups-config") |
| except ValueError: |
| pass |
| infos.system = host_os |
| infos.cpu_family = host_cpu_family |
| infos.cpu = host_cpu |
| infos.endian = host_endian |
| |
| return infos |
| |
| def write_crossfile(infos, ofilename): |
| tmpfilename = ofilename + '~' |
| with open(tmpfilename, 'w') as ofile: |
| ofile.write('[binaries]\n') |
| ofile.write('# Compilers\n') |
| for langname in sorted(infos.compilers.keys()): |
| compiler = infos.compilers[langname] |
| ofile.write(f"{langname} = '{compiler}'\n") |
| ofile.write('\n') |
| |
| ofile.write('# Other binaries\n') |
| for exename in sorted(infos.binaries.keys()): |
| exe = infos.binaries[exename] |
| ofile.write(f"{exename} = '{exe}'\n") |
| ofile.write('\n') |
| |
| ofile.write('[host_machine]\n') |
| ofile.write(f"cpu = '{infos.cpu}'\n") |
| ofile.write(f"cpu_family = '{infos.cpu_family}'\n") |
| ofile.write(f"endian = '{infos.endian}'\n") |
| ofile.write(f"system = '{infos.system}'\n") |
| os.replace(tmpfilename, ofilename) |
| |
| def run(options): |
| if options.debarch: |
| print('Detecting cross environment via dpkg-reconfigure.') |
| infos = detect_debianlike(options) |
| else: |
| #print('Detecting cross environment via environment variables') |
| sys.exit('Can currently only detect debianlike. Patches welcome.') |
| write_crossfile(infos, options.outfile) |
| |
| if __name__ == '__main__': |
| options = parser.parse_args() |
| run(options) |