Example #1
0
 def copy_asset_files(self, files):
     for dst, src in files.items():
         # create dest dir if not exist
         if not os.path.exists(util.split_dir(dst)):
             os.makedirs(util.split_dir(dst))
         # copy file from src to dest
         copyfile(src, dst)
         # check if copy exist
         if os.path.exists(dst):
             continue
         log.fatal('error copying asset file `%s` to `%s`' % (src, dst))
Example #2
0
    def parse_system_input(self, path):
        '''parse system inputs'''
        name, ext = os.path.splitext(path)

        #if ext == '.flux':
        #    print('....parsing module deps....')
        #    # parsingModule.moduleDeps[name]=True

        # check if already imported
        if path in self.imported:
            return
        self.imported[path] = True

        # filter by extension
        if ext == '.a':
            if name.startswith('lib'):
                name = name[3:]
                if self.toolchain == 'msvc':
                    self.lib_files.append(name + '.lib')
                else:
                    self.lib_files.append('-l' + name)
            else:
                log.fatal(
                    'input error: `%s` - library file must be starts with `lib`and ends with `.a` extension.'
                )
        elif ext == '.lib':
            if self.toolchain == 'msvc':
                self.lib_files.append(os.path.basename(path))
            else:
                self.lib_files.append('-l' + name)
        elif ext == '.dylib':
            if self.toolchain == 'gcc':
                self.lib_files.append('-l' + name)
        elif ext == '.framework':
            if self.toolchain == 'gcc':
                self.lib_files.append('-framework ' + name)
        elif ext == '.weak_framework':
            if self.toolchain == 'gcc':
                self.lib_files.append('-weak_framework ' + name)
        elif ext in ['.h', '.hh', '.hxx', '.hpp', '.h++']:
            pass  # ignore
        elif ext == '.flux':
            self.flux_libs.append(name)
        else:
            log.fatal('unrecognized input file type: `%s`' % path)
Example #3
0
    def parse_opts(self, proj_dir, args):
        '''parse build options'''
        self.args = args

        # parse arguments
        i = 0
        for arg in args:
            # options without params
            if arg in ['-v', '-verbose']:
                self.verbose = 1
            elif arg in ['-t', '-time']:
                self.time = True
            elif arg in ['-c', '-clean']:
                self.clean = True
            else:
                # options with params
                if arg.startswith('-'):
                    i = arg.find('=')
                    if i == -1:
                        log.fatal('expected value for option `%s`' % arg)

                    opt, _, val = arg.partition('=')
                    path = util.fix_path(val)
                    if path.startswith('"') and path.endswith('"'):
                        path = path[1:-1]

                    opt = opt.lower()
                    val = val.lower()

                    # outdir (output dir)
                    if opt in ['-o', '-outdir']:
                        # relative to current dir
                        self.outdir = os.path.abspath(
                            os.path.join(proj_dir, path))
                    # apptype
                    elif opt == '-apptype':
                        if val in APP_TYPE:
                            self.apptype = val
                        else:
                            log.fatal(
                                'invalid value for `apptype` option: `{}` - must be {}'
                                .format(val, APP_TYPE))
                    # target
                    elif opt == '-target':
                        if val in target.TARGET or val == 'desktop':
                            self.target = val
                        else:
                            log.fatal(
                                'invalid value for `target` option: `{}` - must be {} or `desktop`'
                                .format(val, target.TARGET))
                    # config
                    elif opt == '-config':
                        if val in target.CONFIG:
                            self.config = val
                        elif val == 'all':
                            self.config = ','.join(target.CONFIG)
                        else:
                            log.fatal(
                                'invalid value for `config` option: `{}` - must be {} or `all`'
                                .format(val, target.CONFIG))
                    # arch
                    elif opt == '-arch':
                        if val in target.ARCH:
                            self.arch = val
                        else:
                            log.fatal(
                                'invalid value for `arch` option: `{}` - must be {}'
                                .format(val, target.ARCH))
                    # verbose
                    elif opt in ['-v', '-verbose']:
                        if val in ['0', '1', '2', '3', '-1']:
                            self.verbose = int(val)
                        else:
                            log.fatal(
                                'invalid value for `verbose` option: `{}` - must be {}'
                                .format(val, "['0', '1', '2', '3' or '-1']"))
                    # profile
                    elif opt == '-profile':
                        #TODO: -profile=windows-msvc-release-x64; macos-release-x64 ; ios-sim-release-arm64 ; emscripten-release-wasm
                        log.todo(
                            'set profile config: <target>-<config>-<arch>[-<tag>]',
                            __file__)
                        pass
                    # tag
                    elif opt == '-tag':
                        self.tag = val
                    else:
                        log.fatal('unrecognized option: `%s`' % arg)
                else:
                    #paths of project file
                    i = args.index(arg)
                    break

        # get project paths
        args = args[i:]

        # adjust build options
        if self.target == '' or self.target == 'desktop':
            self.target = util.get_host_platform()

        self.toolchain = 'gcc'
        if self.target == 'windows-msvc':
            self.toolchain = 'msvc'

        if self.target in target.TARGET_DESKTOP:
            if self.apptype == '':
                self.apptype = APP_TYPE[0]
        elif self.target in target.TARGET and self.target not in target.TARGET_DESKTOP:
            if self.target == 'emscripten':
                if not self.apptype:
                    self.apptype = 'wasm'
                    self.arch = 'wasm'
            else:
                log.todo(
                    "need to ajust other target options (%s)" % self.target,
                    __file__)
        else:
            log.fatal('unrecognized target `%s` or not yet implemented' %
                      self.target)

        if self.apptype in APP_TYPE:
            if self.target not in target.TARGET_DESKTOP:
                log.fatal('`apptype` `%s` is only valid for desktop targets' %
                          self.apptype)
        elif self.apptype == 'wasm':
            if self.target not in target.TARGET_WEB:
                log.fatal(
                    '`apptype` `%s` is only valid for emscripten target' %
                    self.apptype)
        else:
            log.fatal('unrecognized apptype `%s`' % self.apptype)

        # set built profile: <target>-<config>-<arch>[-<tag>]
        self.profile = '-'.join([self.target, self.config, self.arch]) + (
            ('-' + self.tag) if self.tag else '')

        return args
Example #4
0
    def find_msvc(self):

        def find_max_ver_dir(ver_dir):
            max_ver = 0
            max_ver_dir = ''

            for f in os.listdir(ver_dir):
                ver_dir = os.path.join(ver_dir, f)
                if not os.path.isdir(ver_dir):
                    continue
                ver = int(f.replace('.', ''))
                if ver > max_ver:
                    max_ver = ver
                    max_ver_dir = ver_dir
            return max_ver_dir

        if self.toolchain == 'msvc':
            # MSVC
            msvcs = ''
            for ver in self.msvc_version:
                msvcs = os.path.join(os.environ['ProgramFiles(x86)'], 'Microsoft Visual Studio', str(ver).strip())
                if os.path.isdir(msvcs):
                    break
            if not os.path.isdir(msvcs):
                return False

            # Windows Kits
            wkits = os.path.join(os.environ['ProgramFiles(x86)'], 'Windows Kits\\10')
            if not os.path.isdir(wkits):
                return False

            # VC Tools
            tools_dir = ''
            max_ver = 0
            for f in os.listdir(msvcs):
                d = os.path.join(msvcs, f, 'VC\\Tools\\MSVC')
                if not os.path.isdir(d):
                    continue
                
                for ff in os.listdir(d):
                    ver_dir = os.path.join(d, ff)
                    if not os.path.isdir(ver_dir):
                        continue
                    ver = int(ff.replace('.', ''))
                    if ver > max_ver:
                        tools_dir = ver_dir
                        max_ver = ver

            # VC Includes
            incs_dir = find_max_ver_dir(os.path.join(wkits, 'Include'))
            if not incs_dir:
                return False

            # VC Libs
            libs_dir = find_max_ver_dir(os.path.join(wkits, 'Lib'))
            if not libs_dir:
                return False

            # show msvc dirs
            if self.buildopts.verbose >= 3:
                log.info('MSVC installation auto-detected: %s"%s"%s' % (log.YELLOW, msvcs, log.DEFAULT))
                log.info('- VC Tools   = %s"%s"%s' % (log.YELLOW, tools_dir, log.DEFAULT))
                log.info('- VC Include = %s"%s"%s' % (log.YELLOW, incs_dir, log.DEFAULT))
                log.info('- VC Lib     = %s"%s"%s' % (log.YELLOW, libs_dir, log.DEFAULT))

            # set msvc env vars
            if self.buildopts.arch == 'x86':
                os.environ['FLUX_MSVC_PATH'] = tools_dir+'\\bin\\Hostx86\\x86'
                os.environ['FLUX_MSVC_INCLUDE'] = tools_dir+'\\include;'+incs_dir+'\\ucrt;'+incs_dir+'\\shared;'+incs_dir+'\\um;'+incs_dir+'\\winrt'
                os.environ['FLUX_MSVC_LIB'] = tools_dir+'\\lib\\x86;'+libs_dir+'\\ucrt\\x86;'+libs_dir+'\\um\\x86'
            elif self.buildopts.arch == 'x64':
                os.environ['FLUX_MSVC_PATH'] = tools_dir+'\\bin\\Hostx64\\x64'
                os.environ['FLUX_MSVC_INCLUDE'] = tools_dir+'\\include;'+incs_dir+'\\ucrt;'+incs_dir+'\\shared;'+incs_dir+'\\um;'+incs_dir+'\\winrt'
                os.environ['FLUX_MSVC_LIB'] = tools_dir+'\\lib\\x64;'+libs_dir+'\\ucrt\\x64;'+libs_dir+'\\um\\x64'
            else:
                log.fatal('unrecognized architecture build option `%s`' % self.opts.arch)

            return True
        else:
            return False



            
Example #5
0
def run(flux_dir, proj_dir, args):
    flux_dir = util.fix_path(flux_dir)
    proj_dir = util.fix_path(proj_dir)
    curr_dir = proj_dir

    # check space in project path
    if ' ' in proj_dir:
        log.warn(
            'whitespace in project path detected, `flux` will not work correctly'
        )

    # import verbs from flux dir
    verb.import_verbs(flux_dir)

    # parse args
    if len(args) <= 1:
        usage()
    else:
        name = args[1]
        args = args[2:]

        # run available verb
        if name in verb.verbs:
            verb.verbs[name].run(flux_dir, proj_dir, args)

        # for development stuff only
        elif name == 'dev':
            pass
        elif name == 'build':
            #log.text('===== test console output begin =====')
            #log.trace('trace message')
            #log.debug('debug message')
            #log.info('info message')
            #log.warn('warn message')
            #log.error('error message')
            #log.text('===== test console output end =====')

            # set build opts
            opts = BuildOpts()
            args = opts.parse_opts(proj_dir, args)

            # get target datas
            #TODO: add user custom targets

            # set target opts
            target = Target(flux_dir, opts)
            if target.toolchain == 'msvc':
                # check msvc install
                if target.find_msvc():
                    # update env vars
                    os.environ['PATH'] = os.environ[
                        'FLUX_MSVC_PATH'] + ';' + os.environ['PATH']
                    os.environ['INCLUDE'] = os.environ['FLUX_MSVC_INCLUDE']
                    os.environ['LIB'] = os.environ['FLUX_MSVC_LIB']
                else:
                    log.fatal('MSVC installation not found!')
            elif target.target == 'emscripten':
                from mods.sdks import emsdk
                if emsdk.sdk_dir_exists(flux_dir):
                    os.environ[
                        'PATH'] += os.pathsep + emsdk.get_emscripten_dir(
                            flux_dir)

            if opts.verbose >= 3:
                log.info('python %s.%s.%s' % (sys.version_info[:3]))
                log.info('os.environ:')
                for ev in sorted(
                        filter(lambda x: x.startswith('FLUX_'), os.environ)):
                    log.info('- %s: %s' %
                             (ev, log.YELLOW + os.environ[ev] + log.DEFAULT))

            # if not arg, set project in current dir
            if not len(args):
                args += [proj_dir]

            # for each projets
            for arg in args:
                print(log.YELLOW + ("===== `%s`" % arg) + log.DEFAULT)
                arg = util.fix_path(arg)
                path = os.path.join(proj_dir, arg)

                #print(path)

                proj = Project(flux_dir, path, opts)

                # change to project dir
                os.chdir(os.path.abspath(path))

                # clean output dir
                if opts.clean:
                    if opts.verbose >= 1:
                        log.info("cleaning `%s`" % proj.out_dir)
                    proj.clean()

                # create project intermediate dirs
                proj.make_dirs()

                # make Info.plist file
                if proj.target == 'macos' and proj.apptype == 'window':
                    proj.make_info_plist()

                # parse project file
                proj.parse_inputs()

                #print(proj)

                # depends
                if proj.build in ['app']:  # app only?
                    if len(proj.flux_libs):
                        sys_libs = []
                        for lib in proj.flux_libs:
                            # load dep project file
                            dep_dir = os.path.join(
                                util.get_workspace_dir(flux_dir), lib)
                            dep = Project(flux_dir, dep_dir, opts, True)

                            # module or library dep only
                            if dep.build in ['mod', 'lib']:
                                # change dir to dep dir
                                cd = os.getcwd()
                                os.chdir(os.path.abspath(dep_dir))

                                # parse dep project file
                                dep.parse_inputs()

                                # files stamp
                                out_file_stamp = None
                                gen_file_stamp = None

                                # check if module archive exists
                                if not os.path.exists(dep.out_file):
                                    if not os.path.exists(dep.gen_file):
                                        #create dep intermediate dirs
                                        dep.make_dirs()

                                        # generate ninja file for dep
                                        if opts.verbose >= 1:
                                            log.info('generate `%s`' %
                                                     dep.gen_file)
                                        with open(dep.gen_file, 'w') as out:
                                            dep.gen_ninja(out, opts, target)
                                else:
                                    #TODO: regenerate ninja if 'dep.flux_file' is most recent than 'dep.out_file'
                                    pass

                                # add 'dep.gen_file' to project
                                proj.ninja_files.append(dep.gen_file)

                                # build dep module
                                if os.path.exists(dep.gen_file):
                                    if opts.verbose >= 1:
                                        log.info(
                                            'building `%s` %s' %
                                            (dep.base_dir, log.BLUE +
                                             '(dependency)' + log.DEFAULT))
                                    dep.build_ninja(verbose=opts.verbose >= 3)

                                # add dep include dirs (abspath)
                                for inc in dep.include_dirs:
                                    proj.cc_opts.append('-I"%s"' % inc)
                                    proj.cxx_opts.append('-I"%s"' % inc)

                                # add dep module archive
                                proj.lib_files.append('"%s"' % dep.out_file)

                                # append system libs
                                for lib in dep.lib_files:
                                    if lib not in sys_libs:
                                        sys_libs.append(lib)

                                # return to main project
                                os.chdir(cd)

                        # add dep system libs at end
                        for lib in sys_libs:
                            if lib not in proj.lib_files:
                                proj.lib_files.append(lib)

                # set rules vars
                #rule_vars = target.get_rule_vars(proj)

                # generate ninja in proj.out_dir
                if opts.verbose >= 1:
                    log.info('generate `%s`' % proj.gen_file)
                with open(proj.gen_file, 'w') as out:  #StringIO()
                    proj.gen_ninja(out, opts, target)

                # build project from ninja
                if os.path.exists(proj.gen_file):
                    if opts.verbose >= 1:
                        log.info('building `%s`' % proj.base_dir)
                    proj.build_ninja(verbose=opts.verbose >= 3)
                    # copy assets files
                    proj.copy_assets(proj.asset_dir)
                    proj.copy_binaries(proj.out_dir)

            # return to start dir
            os.chdir(curr_dir)
        else:
            log.error('unknown verb `%s`' % name)
Example #6
0
    def parse_local_input(self, path):
        '''parse local inputs'''
        # check if already imported
        if path in self.imported:
            return
        self.imported[path] = True

        # assets
        i = path.find('@/')
        if i != -1:
            src = path[:i]
            if not os.path.exists(src):
                log.error('asset `%s` not found' % src)
                return
            self.asset_files.append(path)
            return

        # get name and extension
        name, ext = os.path.splitext(path)
        name = util.split_name(path)

        # filter by name
        if name == '*':
            path_dir = os.path.dirname(os.path.abspath(path))
            # check dir
            if not os.path.isdir(path_dir) and not path_dir.endswith('**'):
                log.fatal('input directory `%s` not found' % path_dir)
                return

            # filter by extension
            if ext == '.h':
                self.include_dirs.append(path_dir)
                self.cc_opts.append('-I"%s"' % path_dir)
                self.cxx_opts.append('-I"%s"' % path_dir)
            elif ext in ['.hh', '.hxx', '.hpp', '.h++']:
                self.include_dirs.append(path_dir)
                self.cxx_opts.append('-I"%s"' % path_dir)
            elif ext in ['.a', '.lib']:
                if self.toolchain == 'msvc':
                    self.library_dirs.append(path_dir)
                    self.ld_opts.append('-LIBPATH:"%s"' % path_dir)
                else:
                    self.library_dirs.append(path_dir)
                    self.ld_opts.append('-L"%s"' % path_dir)
            elif ext == '.dylib':
                if self.toolchain == 'gcc':
                    self.library_dirs.append(path_dir)
                    self.ld_opts.append('-L"%s"' % path_dir)
            elif ext == '.framework':
                if self.toolchain == 'gcc':
                    self.library_dirs.append(path_dir)
                    self.ld_opts.append('-F"%s"' % path_dir)
            elif ext in [
                    '.c', '.cc', '.cxx', '.cpp', '.c++', '.m', '.mm', '.asm',
                    '.s'
            ]:

                srcs = []
                if sys.version_info[:2] >= (3, 5):
                    srcs = glob.glob(os.path.join(path_dir, name + ext),
                                     recursive=True)
                else:
                    # recursive
                    if path_dir.endswith('**'):
                        path_dir = path_dir[:-3]
                        for dirpaths, _, files in sorted(os.walk(path_dir)):
                            for fn in fnmatch.filter(files, name + ext):
                                srcs.append(os.path.join(dirpaths, fn))
                    else:
                        srcs = glob.glob(os.path.join(path_dir, name + ext))
                if srcs:
                    for src in sorted(srcs):
                        if src in self.imported:
                            continue
                        self.imported[src] = True
                        self.src_files.append(os.path.abspath(src))
            else:
                log.fatal('unrecognized input file filter `%s%s`' %
                          (name, ext))
            return

        # filter by extension
        if ext == '.framework':
            if self.toolchain == 'gcc':
                if not os.path.isdir(path):
                    log.fatal('input framework not found "%s"' % path)
                return
        elif ext == '.flux':
            log.fatal(
                'input: flux module must be defined as a "system" input: `<%s>`'
                % path)
            return
        elif '$(TARGET_ARCH' not in path:
            if os.path.isdir(path):
                self.asset_files.append(path)
                return
            elif not os.path.isfile(path):
                log.fatal('input file not found "%s"' % path)

        if ext in ['.h', '.hh', '.hxx', '.hpp', '.h++']:
            pass  # ignore
        elif ext in [
                '.c', '.cc', '.cxx', '.cpp', '.c++', '.m', '.mm', '.asm', '.s'
        ]:
            self.src_files.append(os.path.abspath(path))
        elif ext == '.java':
            if self.target == 'android':
                self.java_files.append(path)
        elif ext == '.o':
            self.obj_files.append(path)
        elif ext == '.lib':
            self.lib_files.append(path)
        elif ext == '.a':
            if self.toolchain == 'gcc':
                self.lib_files.append('"%s"' % path)
        elif ext in ['.so', '.dylib']:
            if self.toolchain == 'gcc':
                self.lib_files.append('"%s"' % path)
                self.bin_files.append(path)
        elif ext in ['.exe', '.dll']:
            if self.target == 'windows':
                self.bin_files.append(path)
        elif ext == '.framework':
            if self.toolchain == 'gcc':
                #TODO: Ugly!
                #parse_local_input(extract_dir(path)+'/*.framework')
                #parse_system_input(strip_dir(path))
                #self.bin_files.append(path)
                pass
        else:
            self.asset_files.append(path)
Example #7
0
    def __init__(self, flux_dir, proj_dir, build_opts, is_dep=False):
        '''load project file and prepare intermediate dirs'''

        # project yaml datas
        self.data = None

        # init vars
        self.imported = {}

        # project inputs
        self.src_files = []
        self.lib_files = []
        self.obj_files = []
        self.bin_files = []
        self.java_files = []
        self.asset_files = []
        self.ninja_files = []

        # flux project
        self.flux_file = ''
        self.flux_srcs = []
        self.flux_libs = []

        # project build opts
        self.cc_opts = []
        self.cxx_opts = []
        self.ar_opts = []
        self.as_opts = []
        self.ld_opts = []

        self.include_dirs = []
        self.library_dirs = []

        # load project file datas
        proj_dir = util.fix_path(proj_dir)
        proj_file = ''
        if os.path.isdir(proj_dir):
            #log.track('is_dir: '+util.strip_dir(proj_dir), __file__)
            proj_files = [
                os.path.join(proj_dir, FILE),  # flux.yml
                os.path.join(proj_dir,
                             util.strip_dir(proj_dir) +
                             '.yml'),  # <dirname>.yml
                os.path.join(proj_dir,
                             util.strip_dir(proj_dir) +
                             '.flux'),  # <dirname>.flux
            ]
            for file in proj_files:
                #log.track('proj_file: '+file, __file__)
                if os.path.isfile(file):
                    proj_file = file
                    self.data = util.load_flux_yaml(proj_file, build_opts)
                    self.flux_file = proj_file
                    break

        elif os.path.isfile(proj_dir):
            #log.track('is_file: '+file, __file__)
            proj_file = proj_dir
            proj_dir = util.split_dir(proj_dir)
            self.data = util.load_flux_yaml(proj_file, build_opts)
            self.flux_file = proj_file

        if not self.data:
            log.fatal('unable to find project file in `%s`' % proj_dir)

        # get project name in project file else name will be the name of last folder
        self.name = self.data['name'] if self.data.get(
            'name') else util.strip_dir(proj_dir)

        # update build opts
        build_opts.build = self.data['build'] if self.data.get(
            'build') else 'app'
        build_opts.apptype = self.data['type'] if self.data.get(
            'type') else 'window'
        build_opts.build = build.remap(build_opts.build)
        build_opts.target = build.remap(build_opts.target)

        # keep build options for project
        self.build = build_opts.build
        self.apptype = build_opts.apptype if build_opts.build == 'app' else ''  # only for app
        self.profile = build_opts.profile
        self.target = build_opts.target
        self.toolchain = build_opts.toolchain

        # set project directory structure
        if build_opts.outdir and not is_dep:
            self.proj_dir = proj_dir
            self.base_dir = util.fix_path(build_opts.outdir)
            self.build_dir = util.fix_path(
                os.path.join(self.base_dir, self.name))
            self.out_dir = util.fix_path(
                os.path.join(self.build_dir, build_opts.profile))
            self.cache_dir = util.fix_path(
                os.path.join(self.out_dir, CACHE_DIR))
            self.asset_dir = util.fix_path(
                os.path.join(self.out_dir, ASSET_DIR))
        else:
            self.proj_dir = proj_dir
            self.base_dir = util.fix_path(proj_dir)
            self.build_dir = util.fix_path(os.path.join(self.base_dir, FDIR))
            self.out_dir = util.fix_path(
                os.path.join(self.build_dir, build_opts.profile))
            self.cache_dir = util.fix_path(
                os.path.join(self.out_dir, CACHE_DIR))
            self.asset_dir = util.fix_path(
                os.path.join(self.out_dir, ASSET_DIR))

        # get output extension
        self.out_ext = build.EXT[build_opts.target][build_opts.build]
        if (self.target, self.build, self.apptype) == ('macos', 'app',
                                                       'console'):
            self.out_ext = ''  # macos console app

        #if (self.target, self.build) == ('emscripten', 'mod'): # fix emscripten 2.0.17
        #    self.out_file = util.fix_path(os.path.join(self.out_dir, 'lib' + self.name + self.out_ext))
        #else:
        #    self.out_file = util.fix_path(os.path.join(self.out_dir, self.name + self.out_ext))
        self.out_file = util.fix_path(
            os.path.join(self.out_dir, self.name + self.out_ext))

        # set gen file
        self.gen_file = util.fix_path(os.path.join(self.out_dir, NINJA_FILE))

        # get build options
        if 'options' in self.data:
            self.opts = self.data['options'] if self.data.get(
                'options') else {}
            self.cc_opts.append(self.data['options']['cc'] if self.
                                data['options'].get('cc') else '')
            self.cxx_opts.append(self.data['options']['cxx'] if self.
                                 data['options'].get('cxx') else '')
            self.as_opts.append(self.data['options']['as'] if self.
                                data['options'].get('as') else '')
            self.ar_opts.append(self.data['options']['ar'] if self.
                                data['options'].get('ar') else '')
            self.ld_opts.append(self.data['options']['ld'] if self.
                                data['options'].get('ld') else '')

        # add build options for app
        if self.build in ['app', 'application']:
            # add workspace dir in header-dirs
            self.cc_opts.append('-I"%s"' % util.get_workspace_dir(flux_dir))
            self.cxx_opts.append('-I"%s"' % util.get_workspace_dir(flux_dir))
            # add project cache dir in header-dirs
            self.cc_opts.append('-I"%s"' % self.cache_dir)
            self.cxx_opts.append('-I"%s"' % self.cache_dir)
            # add project apptype
            if self.target == 'windows':  #TODO: externalize this
                if self.toolchain == 'msvc':
                    if self.apptype == 'window':
                        self.ld_opts.append('-subsystem:windows')
                    else:
                        self.ld_opts.append('-subsystem:console')
                else:
                    if self.apptype in ['window', 'gui']:
                        self.ld_opts.append('-mwindows')
Example #8
0
    def gen_ninja(self, file, build_opts, target):
        '''generate ninja build file from project'''
        rules_remap = {
            'target.cmds.cc': '$cc',
            'target.cmds.cxx': '$cxx',
            'target.cmds.ar': '$ar',
            'target.cmds.as': '$as',
            'target.cmds.ld': '$ld',
            'target.opts.cc': '$cc_opts_target',
            'target.opts.cxx': '$cxx_opts_target',
            'target.opts.ar': '$ar_opts_target',
            'target.opts.as': '$as_opts_target',
            'target.opts.ld': '$ld_opts_target',
            'project.opts.cc': '$cc_opts_project',
            'project.opts.cxx': '$cxx_opts_project',
            'project.opts.ar': '$ar_opts_project',
            'project.opts.as': '$as_opts_project',
            'project.opts.ld': '$ld_opts_project',
            'project.out.file': '$out',
            'project.libs': '$libs',
            'project.objs': '$objs',
            'project.source': '$in',
            'project.source.dep': '$dep_file',
            'project.source.obj': '$out',  # $obj?
        }

        n = ninja.Writer(file, 150)

        n.comment('flux build system ' + VERSION)
        n.comment('repo: https://github.com/seyhajin/flux')
        n.comment('this file is generated automatically, do not edit!')
        n.newline()
        n.variable('ninja_required_version', ninja_required_version)
        n.newline()
        n.comment('project settings')
        n.variable('proj_name', self.name)
        n.variable('proj_dir', self.proj_dir)
        n.newline()
        n.comment('ninja settings')
        n.variable('builddir', self.cache_dir)
        if self.toolchain == 'msvc':
            if util.python_version[0] >= 3:
                n.variable('msvc_deps_prefix',
                           target.msvc_prefix.encode('utf-8').decode('utf-8'))
            else:
                n.variable('msvc_deps_prefix', unicode(target.msvc_prefix))
        n.newline()
        n.comment('target commands')
        n.variable('cc', target.cmds['cc'])
        n.variable('cxx', target.cmds['cxx'])
        n.variable('as', target.cmds['as'])
        n.variable('ar', target.cmds['ar'])
        n.variable('ld', target.cmds['ld'])
        n.newline()
        n.comment('target options')
        n.variable('cc_opts_target',
                   util.replace_env(target.opts['cc'], os.environ))
        n.variable('cxx_opts_target',
                   util.replace_env(target.opts['cxx'], os.environ))
        n.variable('as_opts_target',
                   util.replace_env(target.opts['as'], os.environ))
        n.variable('ar_opts_target',
                   util.replace_env(target.opts['ar'], os.environ))
        n.variable('ld_opts_target',
                   util.replace_env(target.opts['ld'], os.environ))
        n.newline()
        n.comment('project options')
        cc_opts = ' '.join(self.cc_opts)
        cxx_opts = ' '.join(self.cxx_opts)
        as_opts = ' '.join(self.as_opts)
        ar_opts = ' '.join(self.ar_opts)
        ld_opts = ' '.join(self.ld_opts)
        n.variable('cc_opts_project', util.replace_env(cc_opts, os.environ))
        n.variable('cxx_opts_project', util.replace_env(cxx_opts, os.environ))
        n.variable('as_opts_project', util.replace_env(as_opts, os.environ))
        n.variable('ar_opts_project', util.replace_env(ar_opts, os.environ))
        n.variable('ld_opts_project', util.replace_env(ld_opts, os.environ))

        #TODO: add `subninja` for depends modules : used to include another .ninja file, introduces a new scope
        # `include` used to include another .ninja file in the current scope (use this only for global configurations)
        #if len(self.ninja_files):
        #    n.newline()
        #    n.comment('project depends')
        #    for dep in self.ninja_files:
        #        n.subninja(dep)

        n.newline()
        n.comment('----------------------------')
        n.comment('RULES')
        n.comment('----------------------------')
        n.newline()

        #print(util.replace_env(target.rules['ar'], rules_remap))

        n.rule('cc_compile',
               util.replace_env(target.rules['cc'], rules_remap),
               deps=target.toolchain
               if target.toolchain in ['gcc', 'msvc'] else 'gcc',
               depfile=rules_remap['project.source.dep']
               if self.toolchain == 'gcc' else '',
               description='Compiling $in')
        n.newline()

        n.rule('cxx_compile',
               util.replace_env(target.rules['cxx'], rules_remap),
               deps=target.toolchain
               if target.toolchain in ['gcc', 'msvc'] else 'gcc',
               depfile=rules_remap['project.source.dep']
               if self.toolchain == 'gcc' else '',
               description='Compiling $in')
        n.newline()

        if 'rules' in self.data:
            if 'as' in self.date['rules']:
                n.rule(
                    'as_compile',
                    util.replace_env(target.rules['as'], rules_remap),
                    #deps=target.toolchain if target.toolchain in ['gcc', 'msvc'] else 'gcc',
                    description='Assembling $in')
                n.newline()

        if self.build in ['mod', 'module']:
            n.rule('archive',
                   util.replace_env(target.rules['ar'], rules_remap),
                   description='Archiving $out')
        elif self.build in ['app', 'application']:
            n.rule('link',
                   util.replace_env(target.rules['ld'], rules_remap),
                   description='Linking $out')
        else:
            log.fatal('ninja: unrecognized project build type: `%s`' %
                      self.build)

        n.newline()
        n.comment('----------------------------')
        n.comment('COMPILE')
        n.comment('----------------------------')
        n.newline()

        # for each project source file
        objs = []
        done = {}
        for src in self.src_files:
            ext = util.split_ext(src)
            obj = util.fix_path(
                os.path.join(self.cache_dir,
                             os.path.relpath(src, self.proj_dir)))
            dep = obj + '.d'
            obj += '.obj' if self.toolchain == 'msvc' else '.o'

            # relative paths
            src = util.fix_path(src.replace(self.proj_dir, '$proj_dir'))
            obj = util.fix_path(obj.replace(self.cache_dir, '$builddir'))
            dep = util.fix_path(dep.replace(self.cache_dir, '$builddir'))

            # check if already done
            if obj in done:
                log.fatal('OOPS! collision! contact me!')
            done[obj] = True

            # build statement
            if ext in ['.c', '.m']:
                n.build(obj,
                        'cc_compile',
                        src,
                        variables={'dep_file': dep}
                        if self.toolchain == 'gcc' else {})
            elif ext in ['.cc', '.cxx', '.cpp', '.c++', '.mm']:
                n.build(obj,
                        'cxx_compile',
                        src,
                        variables={'dep_file': dep}
                        if self.toolchain == 'gcc' else {})
            elif ext in ['.asm', '.s']:
                n.build(obj,
                        'as_compile',
                        src,
                        variables={'dep_file': dep}
                        if self.toolchain == 'gcc' else {})

            # add obj to objects list
            objs.append(obj)

        objs += self.obj_files

        # objects alias
        n.newline()
        n.comment('objects alias')
        n.build('objects', 'phony ' + ' '.join(objs))

        if self.build in ['mod', 'module']:
            n.newline()
            n.comment('----------------------------')
            n.comment('ARCHIVE')
            n.comment('----------------------------')
            n.newline()
            n.build(self.out_file,
                    'archive || objects',
                    '',
                    variables={
                        'libs': self.lib_files,
                        'objs': ' '.join(objs),
                    })
        elif self.build in ['app', 'application']:
            n.newline()
            n.comment('----------------------------')
            n.comment('LINK')
            n.comment('----------------------------')
            n.newline()
            n.build(self.out_file,
                    'link || objects',
                    '',
                    variables={
                        'libs': self.lib_files,
                        'objs': ' '.join(objs),
                    })
        else:
            log.fatal('ninja: unrecognized project build type: `%s`' %
                      self.build)

        # project alias
        n.newline()
        n.comment('project alias')
        n.build(self.name, 'phony ' + ninja.escape_path(self.out_file))

        n.newline()
        n.comment('----------------------------')
        n.comment('DEFAULT')
        n.comment('----------------------------')
        n.newline()
        n.build(
            'all',
            'phony %s %s' % (self.name, 'objects'),
        )
        n.newline()
        n.default('all')

        n.newline()
        n.close()