#!/usr/bin/python import sys import os import copy import xml.etree.ElementTree as etree import uuid import getopt import zipfile import shutil EXT_MAPPING = { ".c": "c", ".cc": "cpp", ".cpp": "cpp", ".h": "h", ".s": "s"} def parseError(str): print("*** error: \""+str+"\"\n"); def platformCompare(a, b): return cmp(a.count('*'), b.count('*')) def platformSubseteqTest(a, b): a4=a.split("-") b4=b.split("-") ret=len(a4)==len(b4) i=0 while i0: p=p+"-" p=p+p4[j] if len(p)>0: ret.append(p) ret.sort(fallbackCompare) return ret def updateCtx(conf, ctx, node): if "root" in node.attrib: root=ctx["root"] ctx=copy.copy(ctx) rel_prj_path=os.path.split(ctx["root"])[1] prjconfigdir=os.path.join(ctx["config"], rel_prj_path, "config") # print "rel_prj_path="+rel_prj_path+" prjconfigdir="+prjconfigdir v=node.attrib["root"].format(platform=ctx["platform"], config=os.path.join(ctx["config"], "config"), prjconfig=prjconfigdir) f=node.attrib["root"].format(platform="{platform}", config=os.path.join(ctx["config"], "config"), prjconfig=prjconfigdir) if v!=f: conf["format"][os.path.join(root, v)]=os.path.join(root, f) ctx_root=os.path.join(root, v) if not os.path.exists(ctx_root): list=generateFallbackList(ctx["platform"]) for p in list: v=node.attrib["root"].format(platform=p, config=os.path.join(ctx["config"], "config"), prjconfig=prjconfigdir) if os.path.exists(os.path.join(root, v)): map=os.path.join(root, v) conf["mapping"][map]=ctx_root ctx_root=map list=[] if not os.path.exists(ctx_root) and "platforms" in conf and ctx["platform"] in conf["platforms"] and "family" in conf["platforms"][ctx["platform"]]: family=conf["platforms"][ctx["platform"]]["family"] list=generateFallbackList(family) # print "list="+str(list) for p in list: v=node.attrib["root"].format(platform=p, config=os.path.join(ctx["config"], "config"), prjconfig= prjconfigdir) if os.path.exists(os.path.join(root, v)): map=os.path.join(root, v) conf["mapping"][map]=ctx_root ctx_root=map list=[] ctx["root"]=ctx_root return ctx def parseDefines(ctx, node, dict): value=None if "value" in node.attrib: value=node.attrib["value"] if "name" in node.attrib: name=node.attrib["name"] dict[name]=value else: parseError("define syntax invalid ("+nv+")"); def parseSettings(conf, node, ctx, lib): if node.tag=="settings": tag="defines" elif node.tag=="export": tag="exports" else: parseError("unknown setting: "+node.tag); for child in list(node): if child.tag=="define": parseDefines(ctx, child, lib[tag]) else: parseError("unhanded element: "+child.tag) def parseDeps(node): if "dep" in node.attrib: dep=node.attrib["dep"].split() return dep else: return [] def parseLibrary(conf, node, ctx, seq_type): lib_name=node.attrib["name"] lib_uuid=uuid.uuid5(uuid.NAMESPACE_URL, "urn:lib:"+lib_name) lib={"name": lib_name, "uuid": lib_uuid, "source": { "files": []}, "header": { "files": [], "target": "", "includes": [] }, "defines": {}, "exports": {}, "deps": parseDeps(node), "mode": "c90", "align": "", "external": False } ctx=updateCtx(conf, ctx, node) setAttr(lib, node, "mode") setAttr(lib, node, "align") if not(lib_name in ctx["externals"]) or not("external" in ctx["externals"][lib_name]) or not(ctx["externals"][lib_name]["external"]): for child in list(node): if child.tag=="source": parseFiles(lib["source"]["files"], list(child), updateCtx(conf, ctx, child)) elif child.tag=="header": setAttr(lib["header"], child, "target") child_ctx=updateCtx(conf, ctx, child) lib["header"]["includes"].append(child_ctx["root"]) parseFiles(lib["header"]["files"], list(child), child_ctx) elif child.tag=="settings": parseSettings(conf, child, ctx, lib) elif child.tag=="export": parseSettings(conf, child, ctx, lib) else: parseError("unhanded element: "+child.tag) else: sys.stderr.write("using external "+lib_name) lib["external"]=True conf[seq_type].append(lib) def isExcluded(conf, ctx, lib): # sys.stderr.write conf["platforms"] if ctx["platform"] in conf["platforms"]: platform=conf["platforms"][ctx["platform"]] return lib in platform["exclude"] else: return False def parsePlatform(conf, node, ctx): if "name" in node.attrib: name=node.attrib["name"] platform={ "exclude": {}, "libs": [], "ldflags": "" } setAttr(platform, node, "family") setAttr(platform, node, "cc") setAttr(platform, node, "ar") setAttr(platform, node, "ld") setAttr(platform, node, "cflags") setAttr(platform, node, "cflags_c") setAttr(platform, node, "cflags_cpp") setAttr(platform, node, "cppflags") setAttr(platform, node, "ldflags") setAttr(platform, node, "host") if "exclude" in node.attrib: for prj in node.attrib["exclude"].split(" "): platform["exclude"][prj]=None # sys.stderr.write platform["exclude"] if "libs" in node.attrib: platform["libs"].extend(node.attrib["libs"].split(" ")) conf["platforms"][name]=platform else: parseError("no name given for platform") def parseTargets(conf, node, ctx): for child in list(node): if child.tag=="include": path=os.path.abspath(os.path.join(ctx["root"], child.attrib["path"])) new_ctx=copy.copy(ctx) new_ctx["root"]=os.path.dirname(path) parseConfiguration(conf, path, new_ctx) elif child.tag=="library": parseLibrary(conf, child, ctx, "libraries") elif child.tag=="tool": parseLibrary(conf, child, ctx, "tools") elif child.tag=="platform": parsePlatform(conf, child, ctx) else: parseError("unhanded element: "+child.tag) def parseConfiguration(conf, filename, ctx): sys.stderr.write("parsing "+filename+"\n") tree=etree.parse(filename) if tree is not None: parseTargets(conf, tree.getroot(), ctx) else: parseError("failed to open file \""+filename+"\"") def depClosure2(conf, deps, ignoreExternal): ret=[] gray=set(deps) black=set() while len(gray)>0: for lib in conf["libraries"]: if lib["name"] in gray: gray.remove(lib["name"]) black.add(lib["name"]) if not(ignoreExternal) or not(lib["external"]): ret.append((lib, [])) lib_deps=lib["deps"] for lib_dep in lib_deps: if not lib_dep in black: gray.add(lib_dep) return ret def depCompare(a, b): if a[0] in b[1]: return 1 elif b[0] in a[1]: return -1 else: return 0 def depClosureStr(req_deps, deps): ret="depClosure("+str(req_deps)+") =" for lib in deps: ret=ret+" "+lib[0]["name"]+"<" for x in lib[1]: ret=ret+" "+x[0]["name"] ret=ret+" >" return ret def depClosure(conf, req_deps, ignoreExternal): deps=depClosure2(conf, req_deps, ignoreExternal) for lib in deps: lib[1].extend(depClosure2(conf, lib[0]["deps"], ignoreExternal)) # print depClosureStr(req_deps, deps) # deps.sort(depCompare) # print depClosureStr(req_deps, deps) ret=[] for lib in deps: ret.append(lib[0]["name"]) # print "\n" return ret def gatherIncludeDirs(conf, ctx, deps): ret=[] aux={} for lib in conf["libraries"]: if lib["name"] in deps: for file in lib["header"]["files"]: if file["install"] is not None: dir=os.path.dirname(file["path"]) dir=os.path.abspath(dir.rstrip(file["install"])) dir=os.path.relpath(dir, ctx["base"]) if dir not in aux: aux[dir]=None ret.append(dir) # sys.stderr.write ret return ret def gatherSources(conf, ctx, lib): sources=[] for file in lib["source"]["files"]: rel_source=os.path.relpath(file["path"], ctx["base"]) sources.append((rel_source, file)) return sources #def generateOBJS(conf, ctx, lib, out, obj_dir, cppflags): # objs=[] # for file in lib["source"]["files"]: # rel_source=os.path.relpath(file["path"], ctx["base"]) # rel_obj=os.path.join(obj_dir, os.path.splitext(rel_source)[0]+".o") # out_dir=os.path.dirname(rel_obj) # out.write(rel_obj+": "+rel_source+"\n") # out.write("\t@mkdir -p "+out_dir+"\n") # specific="" # if file["ext"]=="c": # specific ="$(CFLAGS_C) " # elif file["ext"]=="cpp": # specific ="$(CFLAGS_CPP) " # out.write("\t$(CC) -c $(CFLAGS) "+ specific +"$(CPPFLAGS)"+cppflags+" "+ rel_source+" -o "+rel_obj+"\n") # objs.append(rel_obj) # return objs def generateDEPS(conf, ctx, lib, out, obj_dir, cppflags, filename): for file in lib["source"]["files"]: rel_source=os.path.relpath(file["path"], ctx["base"]) specific="" if file["ext"]=="c": specific ="$(CFLAGS_C) " elif file["ext"]=="cpp": specific ="$(CFLAGS_CPP) " out.write("\tmakedepend -a -f"+filename+" $(CPPFLAGS)"+cppflags+" "+ rel_source+"\n") def generateCPPFLAGS(conf, ctx, lib, build_dir): cppflags="" for define in lib["defines"]: if lib["defines"][define] is None: cppflags=cppflags+" -D"+define else: cppflags=cppflags+" -D"+define+"="+lib["defines"][define] for dir in lib["header"]["includes"]: abs_dir=os.path.abspath(dir) rel_dir=os.path.relpath(abs_dir, os.path.join(ctx["base"], build_dir)) # sys.stderr.write("abs_dir="+str(abs_dir)+" build_dir="+os.path.join(ctx["base"], build_dir)+" rel_dir="+str(rel_dir)) cppflags=cppflags+" -I"+rel_dir dep_closure=depClosure(conf, lib["deps"], False) dep_dirs=gatherIncludeDirs(conf, ctx, dep_closure) for dir in dep_dirs: abs_dir=os.path.abspath(dir) rel_dir=os.path.relpath(abs_dir, os.path.join(ctx["base"], build_dir)) # sys.stderr.write("abs_dir="+str(abs_dir)+" build_dir="+os.path.join(ctx["base"], build_dir)+" rel_dir="+str(rel_dir)) cppflags=cppflags+" -I"+rel_dir for dep_lib in conf["libraries"]: if dep_lib["name"] in ctx["externals"]: ext_lib=ctx["externals"][dep_lib["name"]] if "external" in ext_lib and ext_lib["external"]: if "cppflags" in ext_lib: cppflags=cppflags+" "+ext_lib["cppflags"] return cppflags def generateVCXPROJ(conf, ctx, lib, type): filename=os.path.abspath("win32\\"+lib["name"]+"\\"+lib["name"]+".vcxproj") filepath=os.path.dirname(filename) prj_uuid=lib["uuid"] sys.stderr.write("generating "+filename+"\n") try: os.makedirs(os.path.dirname(filename)) except OSError: pass out=open(filename, "w") out.write("\n"); out.write("\n"); out.write(" \n"); out.write(" Debug\n"); out.write(" Win32\n"); out.write(" \n"); out.write("\n"); out.write(" Release\n"); out.write(" Win32\n"); out.write("\n"); out.write("\n"); out.write("\n"); out.write(" {"+str(prj_uuid)+"}\n"); out.write(" Win32Proj\n"); out.write(" "+lib["name"]+"\n"); out.write("\n"); out.write("\n"); out.write(" \n"); out.write(" "+type+"\n"); out.write(" true\n"); out.write(" Unicode\n"); out.write(" \n"); out.write(" \n"); out.write(" "+type+"\n"); out.write(" false\n"); out.write(" true\n"); out.write(" Unicode\n"); out.write(" \n"); out.write("\n"); out.write("\n"); out.write("\n"); out.write("\n"); out.write("\n"); out.write("\n"); out.write("\n"); dep_closure=depClosure(conf, lib["deps"], False) cpp_defs="WIN32;" for define in lib["defines"]: if lib["defines"][define] is None: cpp_defs=cpp_defs+define+";" else: cpp_defs=cpp_defs+define+"="+lib["defines"][define]+";" for dep in dep_closure: for dep_lib in conf["libraries"]: if dep_lib["name"]==dep and not isExcluded(conf, ctx, dep): for define in dep_lib["exports"]: if dep_lib["exports"][define] is None: cpp_defs=cpp_defs+define+";" else: cpp_defs=cpp_defs+define+"="+dep_lib["defines"][define]+";" cpp_defs=cpp_defs+"_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)" out.write(""+cpp_defs+"\n" ) AdditionalIncludeDirectories="" for dir in lib["header"]["includes"]: AdditionalIncludeDirectories=AdditionalIncludeDirectories+os.path.relpath(os.path.abspath(dir), filepath)+";" dep_dirs=gatherIncludeDirs(conf, ctx, dep_closure) for dir in dep_dirs: abs_path=os.path.relpath(os.path.abspath(dir), filepath) AdditionalIncludeDirectories=AdditionalIncludeDirectories+abs_path+";" AdditionalIncludeDirectories=AdditionalIncludeDirectories+"%(AdditionalIncludeDirectories)" out.write(""+AdditionalIncludeDirectories+"\n") if "c99"==lib["mode"]: out.write("CompileAsCpp\n"); if ""!=lib["align"]: out.write(""+lib["align"]+"Byte\n"); out.write("\n"); if "Application"==type: out.write("\n"); out.write("") if ctx["platform"] in conf["platforms"]: ext_libs=conf["platforms"][ctx["platform"]]["libs"] else: ext_libs={} # sys.stderr.write ext_libs for ext_lib in ext_libs: # sys.stderr.write ext_lib out.write(ext_lib+";") out.write("%(AdditionalDependencies) \n") out.write("\n"); out.write("\n"); out.write("\n") out.write("\n"); out.write("Level3\n") out.write("Disabled\n") out.write("4996\n") out.write("\n"); if "Application"==type: out.write("\n"); out.write("true\n") out.write("Console\n") out.write("\n"); out.write("\n"); out.write("\n") out.write("\n") out.write("MaxSpeed\n") out.write("4996\n") out.write("true \n") out.write("true \n") out.write("\n"); if "Application"==type: out.write("\n"); out.write("false\n") out.write("Console\n") out.write("true\n") out.write("true\n") out.write("\n"); out.write("\n"); out.write("\n"); for file in lib["header"]["files"]: if "h"==file["ext"]: out.write(" \n"); out.write("\n"); out.write("\n"); for file in lib["source"]["files"]: if "cpp"==file["ext"] or "c"==file["ext"] or "s"==file["ext"]: out.write(" \n"); out.write(" \n"); out.write("\n"); out.write("\n"); for dep in dep_closure: for dep_lib in conf["libraries"]: if dep_lib["name"]==dep and not isExcluded(conf, ctx, dep_lib["name"]): out.write("\n") out.write("{"+str(dep_lib["uuid"])+"}\n") out.write("\n") out.write("\n") out.write("\n"); out.write("\n"); out.write("\n"); out.close() def writeProject(out, solution_uuid, lib): out.write("Project(\"{"+str(solution_uuid)+"}\") = \""+lib["name"]+"\", \""+lib["name"]+"\\"+lib["name"]+".vcxproj\", \"{"+str(lib["uuid"])+"}\"\n") out.write("EndProject\n") def generatePlatformList(conf, ctx): add=[] for platform in conf["platforms"]: if platformSubseteqTest(ctx["platform"], platform): add.append(platform) add.sort(platformCompare) return add def generateConfiguration(ctx, includes, platform): conf={ "libraries": [], "tools": [], "platforms": {}, "mapping": {}, "format": {} } ctx["platform"]=platform for include in includes: parseConfiguration(conf, include, ctx) if ctx["platform"] not in conf["platforms"]: add=generatePlatformList(conf, ctx); if len(add)>0: conf["platforms"][ctx["platform"]]=conf["platforms"][add[0]] return conf def generateWin32(ctx, source): platform=ctx["platforms"][0] conf=generateConfiguration(ctx, [source], platform) sys.stderr.write("generate win32 project") for lib in conf["libraries"]: if not isExcluded(conf, ctx, lib["name"]): generateVCXPROJ(conf, ctx, lib, "StaticLibrary") for tool in conf["tools"]: if not isExcluded(conf, ctx, tool["name"]): generateVCXPROJ(conf, ctx, tool, "Application") solution_file=os.path.abspath("win32\\solution.sln") solution_uuid=uuid.uuid5(uuid.NAMESPACE_URL, solution_file) out=open(solution_file, "w") out.write("\n") out.write("Microsoft Visual Studio Solution File, Format Version 11.00\n") for lib in conf["libraries"]: if not isExcluded(conf, ctx, lib["name"]): writeProject(out, solution_uuid, lib) for tool in conf["tools"]: if not isExcluded(conf, ctx, tool["name"]): writeProject(out, solution_uuid, tool) out.write("\n") out.close() def writeSourceRules(conf, ctx, lib_type, out, lib, build_dir): dirs={} sources=gatherSources(conf, ctx, lib) out.write("objs_"+lib["name"]+"=\\\n") for source in sources: out.write(" $(BUILD_DIR)/"+os.path.splitext(source[0])[0]+".o\\\n") dirs[os.path.dirname(source[0])]=None out.write(" \n") out.write(lib["name"]+"_includes="+generateCPPFLAGS(conf, ctx, lib, build_dir)+"\n") out.write("\n") includes="$("+lib["name"]+"_includes)" lib_type_flags="" if lib_type=="shared": if platformSubseteqTest(ctx["platform"], "linux-*-gcc-*"): lib_type_flags=" -fPIC -DPIC" elif platformSubseteqTest(ctx["platform"], "darwin-*-gcc-*"): lib_type_flags=" -fno-common" # write special rules for source in sources: file=source[1] if "x" in file: special="-x "+file["x"]+" " out.write("$(BUILD_DIR)/"+os.path.splitext(source[0])[0]+".o: $(SRC_DIR)/"+source[0]+"\n") out.write("\t@mkdir -p $(dir $@)\n") out.write("\t$(CC) $(CFLAGS) $(CFLAGS_C) $(CPPFLAGS) "+special+includes+lib_type_flags+" -c \"$<\" -o \"$@\"\n") # write generic rules for dir in dirs: for ext in EXT_MAPPING: if EXT_MAPPING[ext]=='c' or EXT_MAPPING[ext]=='s': out.write("$(BUILD_DIR)/"+dir+"/%.o: $(SRC_DIR)/"+dir+"/%"+ext+"\n") out.write("\t@mkdir -p $(dir $@)\n") out.write("\t$(CC) $(CFLAGS) $(CFLAGS_C) $(CPPFLAGS) "+includes+lib_type_flags+" -c \"$<\" -o \"$@\"\n") out.write("\n") elif EXT_MAPPING[ext]=='cpp': out.write("$(BUILD_DIR)/"+dir+"/%.o: $(SRC_DIR)/"+dir+"/%"+ext+"\n") out.write("\t@mkdir -p $(dir $@)\n") out.write("\t$(CC) $(CFLAGS) $(CFLAGS_CPP) $(CPPFLAGS) "+includes+lib_type_flags+" -c \"$<\" -o \"$@\"\n") out.write("\n") def writeMakefileFlags(conf, ctx, out): platform=ctx["platform"] out.write("CC="+conf["platforms"][platform]["cc"]+"\n"); out.write("AR="+conf["platforms"][platform]["ar"]+"\n"); out.write("CFLAGS="+conf["platforms"][platform]["cflags"]+"\n") out.write("CFLAGS_C="+conf["platforms"][platform]["cflags_c"]+"\n") out.write("CFLAGS_CPP="+conf["platforms"][platform]["cflags_cpp"]+"\n") out.write("CPPFLAGS="+conf["platforms"][platform]["cppflags"]+"\n"); out.write("LDFLAGS="+conf["platforms"][platform]["ldflags"]+"\n"); def getSharedExt(conf, ctx): if platformSubseteqTest(ctx["platform"], "darwin-*-gcc-*"): return ".dylib" else: return ".so" def generateExtLDFlags(conf, ctx): ext_ldflags="" for dep_lib in conf["libraries"]: if dep_lib["name"] in ctx["externals"]: ext_lib=ctx["externals"][dep_lib["name"]] if "external" in ext_lib and ext_lib["external"]: if "ldflags" in ext_lib: ext_ldflags=ext_ldflags+" "+ext_lib["ldflags"] return ext_ldflags def generateLDFlags(conf, ctx, lib_type, initial_deps, exclude_deps, lib_form): ret="" deps=depClosure(conf, initial_deps, True) for dep in deps: if not(dep in exclude_deps): if lib_type=="static": ret=ret+" $(BUILD_DIR)/lib"+dep+".a" if lib_type=="shared": if lib_form: ret=ret+" -L$(BUILD_DIR) -l"+dep else: ret=ret+" $(BUILD_DIR)/lib"+dep+getSharedExt(conf, ctx) return ret def generateLibraryMakefile(conf, ctx, lib_type, lib, filename, build_dir, src_dir): sys.stderr.write("generating "+filename+"\n") if not os.path.exists(os.path.dirname(filename)): os.makedirs(os.path.dirname(filename)) out=open(filename, "w") out.write("# Generated.\n") # compiler flags writeMakefileFlags(conf, ctx, out) out.write("BUILD_DIR=.\n") out.write("SRC_DIR="+src_dir+"\n") out.write("\n") out.write(".PHONY: all clean\n") out.write("\n") out.write("# library "+lib["name"]+"\n") out.write("all:") if lib_type=="static": out.write(" $(BUILD_DIR)/lib"+lib["name"]+".a") if lib_type=="shared": out.write(" $(BUILD_DIR)/lib"+lib["name"]+getSharedExt(conf, ctx)) out.write("\n\n") writeSourceRules(conf, ctx, lib_type, out, lib, build_dir) if lib_type=="static": out.write("$(BUILD_DIR)/lib"+lib["name"]+".a: $(objs_"+lib["name"]+")\n") out.write("\t$(AR) -rcs $(BUILD_DIR)/lib"+lib["name"]+".a $(objs_"+lib["name"]+")\n") out.write("\n") if lib_type=="shared": ld_deps=generateLDFlags(conf, ctx, lib_type, lib["deps"], [lib["name"]], True)+generateExtLDFlags(conf, ctx) out.write("$(BUILD_DIR)/lib"+lib["name"]+getSharedExt(conf, ctx)+": $(objs_"+lib["name"]+")\n") if platformSubseteqTest(ctx["platform"], "darwin-*-gcc-*"): out.write("\t$(CC) -dynamiclib -install_name lib"+lib["name"]+getSharedExt(conf, ctx)+" -o $(BUILD_DIR)/lib"+lib["name"]+getSharedExt(conf, ctx)+" $(objs_"+lib["name"]+")"+ld_deps+"\n") else: out.write("\t$(CC) -shared -Wl,-soname,lib"+lib["name"]+getSharedExt(conf, ctx)+" -Wl,-z,defs -fPIC -o $(BUILD_DIR)/lib"+lib["name"]+getSharedExt(conf, ctx)+" $(objs_"+lib["name"]+")"+ld_deps+" -lc\n") out.write("\tstrip --remove-section=.comment --remove-section=.note --strip-unneeded $(BUILD_DIR)/lib"+lib["name"]+getSharedExt(conf, ctx)) out.write("\n") out.write("clean:\n") out.write("\trm -rf $(BUILD_DIR)/lib"+lib["name"]+".a $(BUILD_DIR)/lib"+lib["name"]+getSharedExt(conf, ctx)+" $(objs_"+lib["name"]+")\n") out.close() def generateLibraryInclude(conf, ctx, lib, filename, build_dir, src_dir): sys.stderr.write("generating "+filename+"\n") if not os.path.exists(os.path.dirname(filename)): os.makedirs(os.path.dirname(filename)) ret=[] lib_deps=lib["deps"] lib_deps.append(lib["name"]) # out.write("deps="+str(lib["deps"])+"\n"); dep_closure=depClosure(conf, lib_deps, False) dep_dirs=gatherIncludeDirs(conf, ctx, dep_closure) for dep in dep_dirs: dep_dir=os.path.join(ctx["base"], str(dep)) if dep_dir in conf["mapping"]: dep_dir=conf["mapping"][dep_dir] if dep_dir in conf["format"]: ln_src=os.path.join(build_dir, "include", os.path.relpath(conf["format"][dep_dir], ctx["base"]).format(platform="platform").replace(os.sep, "_")) ln_dst=os.path.join(src_dir, dep) if os.path.exists(ln_src): os.remove(ln_src) print("symlink("+ln_dst+", "+ln_src+")"+str(os.path.exists(ln_src))) os.symlink(ln_dst, ln_src) ret.append(ln_src) else: ret.append(dep) out=open(filename, "w") for file in ret: out.write(file+"\n") out.close() def generateToolMakefile(conf, ctx, lib_type, tool, filename, build_dir, src_dir): sys.stderr.write("generating "+filename+"\n") if not os.path.exists(os.path.dirname(filename)): os.makedirs(os.path.dirname(filename)) out=open(filename, "w") out.write("# Generated.\n") # compiler flags writeMakefileFlags(conf, ctx, out) out.write("BUILD_DIR=.\n") out.write("SRC_DIR="+src_dir+"\n") out.write("\n") out.write(".PHONY: all clean\n") out.write("\n") out.write("# tool "+tool["name"]+"\n") out.write("all: $(BUILD_DIR)/"+ tool["name"]+"\n\n") writeSourceRules(conf, ctx, "static", out, tool, build_dir) out.write(tool["name"]+"_ld="+generateLDFlags(conf, ctx, lib_type, tool["deps"], [], False)+"\n") # deps=depClosure(conf, tool["deps"], True) # for dep in deps: # if lib_type=="static": # out.write(" $(BUILD_DIR)/lib"+ dep +".a") # if lib_type=="shared": # out.write(" $(BUILD_DIR)/lib"+ dep +getSharedExt(conf, ctx)) # out.write("\n") ext_ldflags=generateExtLDFlags(conf, ctx) # ext_ldflags="" # for dep_lib in conf["libraries"]: # if dep_lib["name"] in ctx["externals"]: # ext_lib=ctx["externals"][dep_lib["name"]] # if "external" in ext_lib and ext_lib["external"]: # if "ldflags" in ext_lib: # ext_ldflags=ext_ldflags+" "+ext_lib["ldflags"] out.write("$(BUILD_DIR)/"+tool["name"]+": $(objs_"+tool["name"]+") $("+tool["name"]+"_ld)\n") static_flag="" if lib_type=="static" and platformSubseteqTest(ctx["platform"], "linux-*-gcc-*"): static_flag=" --static" out.write("\t$(CC) $(CFLAGS) $(CPPFLAGS) -o $(BUILD_DIR)/"+tool["name"]+" $(objs_"+tool["name"]+") "+generateLDFlags(conf, ctx, lib_type, tool["deps"], [], True)+ ext_ldflags+" $(LDFLAGS)\n") out.write("\n") out.write("clean:\n") out.write("\trm -f $(BUILD_DIR)/"+tool["name"]+" $(objs_"+tool["name"]+")\n") def generateTypedMakefile(conf, ctx, lib_type): obj_dir=os.path.join("build", ctx["platform"], lib_type) filename=os.path.join(obj_dir, "Makefile") sys.stderr.write("generating "+filename+"\n") if not os.path.exists(os.path.dirname(filename)): os.makedirs(os.path.dirname(filename)) out=open(filename, "w") out.write("# Generated.\n") # generate phony targets out.write(".PHONY: all clean tools dep") for lib in conf["libraries"]: if not lib["external"]: out.write(" "+lib["name"]) for tool in conf["tools"]: out.write(" "+tool["name"]) out.write("\n") # all out.write("all:") for lib in conf["libraries"]: if not lib["external"]: out.write(" "+lib["name"]) out.write(" tools\n") # tools out.write("tools:") for tool in conf["tools"]: out.write(" "+tool["name"]) out.write("\n") # generate libs for lib in conf["libraries"]: if not lib["external"]: makefile=os.path.join(obj_dir, "Makefile."+lib["name"]) generateLibraryMakefile(conf, ctx, lib_type, lib, makefile, obj_dir, os.path.join("..", "..", "..")) libincludefile=os.path.join(obj_dir, "include", lib["name"]+".inc") generateLibraryInclude(conf, ctx, lib, libincludefile, obj_dir, os.path.join("..", "..", "..", "..")) out.write(lib["name"]+":") deps=depClosure(conf, lib["deps"], True) for dep in deps: if lib["name"]!=dep: out.write(" "+dep) out.write("\n") out.write("\t$(MAKE) -f "+"Makefile."+lib["name"]+"\n\n") # generate tools for tool in conf["tools"]: makefile=os.path.join(obj_dir, "Makefile."+tool["name"]) generateToolMakefile(conf, ctx, lib_type, tool, makefile, obj_dir, os.path.join("..", "..", "..")) deps=depClosure(conf, tool["deps"], True) out.write(tool["name"]+":") for dep in deps: if tool["name"]!=dep: out.write(" "+dep) out.write("\n") out.write("\t$(MAKE) -f "+"Makefile."+ tool["name"]+"\n\n") out.write("clean:\n") for lib in conf["libraries"]: if not lib["external"]: out.write("\t$(MAKE) -f "+"Makefile."+lib["name"]+" clean\n") for tool in conf["tools"]: out.write("\t$(MAKE) -f "+"Makefile."+tool["name"]+" clean\n") # out.write("dep:\n") # for lib in conf["libraries"]: # generateDEPS(conf, ctx, lib, out, obj_dir, generateCPPFLAGS(conf, ctx, lib), filename) # for tool in conf["tools"]: # generateDEPS(conf, ctx, tool, out, obj_dir, generateCPPFLAGS(conf, ctx, tool), filename) out.write("package: all\n") out.write("\tcd ../../.. && ./generate.py --include Makefile.xml"); for ext_lib in ctx["externals"]: if ctx["externals"][ext_lib]["external"]: name=ext_lib if "xml"==ext_lib: name="libxml" out.write(" --with-"+name+"=yes") if "cppflags" in ctx["externals"][ext_lib]: out.write(" --with-"+name+"-cppflags=\""+ctx["externals"][ext_lib]["cppflags"]+"\"") if "ldflags" in ctx["externals"][ext_lib]: out.write(" --with-"+name+"-ldflags=\""+ctx["externals"][ext_lib]["ldflags"]+"\"") out.write(" --package package_"+lib_type+".zip --type "+lib_type) out.write(" --config-dir "+ctx["config"]+" "+ctx["platform"]) out.write("\n") obj_dir=os.path.join(ctx["base"], "build", ctx["platform"], lib_type) tool_ext="" if lib_type=="static": lib_ext=".a" else: lib_ext=getSharedExt(conf, ctx) lib_prefix="lib" base="$(DESTDIR)/usr/" out.write("install: all\n") for lib in conf["libraries"]: if not lib["external"] and not isExcluded(conf, ctx, lib["name"]): for include in lib["header"]["files"]: if None!=include["install"]: target=base+"include/" if len(include["install"])>0: target=target+include["install"]+"/" target=target+os.path.split(include["path"])[1] out.write("\t@mkdir -p "+os.path.dirname(target)+"\n") out.write("\t@cp "+include["path"]+" "+target+"\n") target=base+"lib/"+lib_prefix+lib["name"]+lib_ext out.write("\t@mkdir -p "+os.path.dirname(target)+"\n") if lib_type=="shared": out.write("\t@cp "+os.path.join(obj_dir, lib_prefix+lib["name"]+lib_ext)+" "+target+".1\n") out.write("\tldconfig -v -n "+os.path.dirname(target)+"\n") else: out.write("\t@cp "+os.path.join(obj_dir, lib_prefix+lib["name"]+lib_ext)+" "+target+"\n") for tool in conf["tools"]: if not isExcluded(conf, ctx, tool["name"]): target=base+"bin/"+tool["name"]+tool_ext out.write("\t@mkdir -p "+os.path.dirname(target)+"\n") out.write("\t@cp "+os.path.join(obj_dir, tool["name"]+tool_ext)+" "+target+"\n") target=base+"lib/pkgconfig/libopc.pc" out.write("\t@mkdir -p "+os.path.dirname(target)+"\n") out.write("\t@cp "+os.path.join(ctx["base"], "config", "libopc.pc")+" "+target+"\n") out.close() def generateTypedMakefiles(ctx, source, lib_types): for platform in ctx["platforms"]: conf=generateConfiguration(ctx, [source], platform) if ctx["platform"] in conf["platforms"]: for lib_type in lib_types: generateTypedMakefile(conf, ctx, lib_type) else: parseError("platform "+ctx["platform"]+" is unknown.") sys.stderr.write("available platforms:"); for platform in conf["platforms"]: sys.stderr.write(platform+"\n") out=open("Makefile", "w") out.write(".PHONY: all clean"); for platform in ctx["platforms"]: for lib_type in lib_types: out.write(" "+platform+"."+lib_type); for lib_type in lib_types: out.write(" "+lib_type); out.write("\n"); out.write("all:"); for lib_type in lib_types: out.write(" "+lib_type); out.write("\n"); for lib_type in lib_types: out.write(lib_type+":"); for platform in ctx["platforms"]: out.write(" "+platform+"."+lib_type); out.write("\n"); for lib_type in lib_types: for platform in ctx["platforms"]: out.write(platform+"."+lib_type+": build"+os.sep+platform+os.sep+lib_type+os.sep+"Makefile\n"); out.write("\t@$(MAKE) -C build"+os.sep+platform+os.sep+lib_type+"\n"); out.write("clean:\n") for lib_type in lib_types: for platform in ctx["platforms"]: out.write("\t@$(MAKE) -C build"+os.sep+platform+os.sep+lib_type+" clean\n"); out.write("package:\n") for lib_type in lib_types: for platform in ctx["platforms"]: out.write("\t@$(MAKE) -C build"+os.sep+platform+os.sep+lib_type+" package\n") out.write("install:\n") for lib_type in lib_types: for platform in ctx["platforms"]: out.write("\t@$(MAKE) -C build"+os.sep+platform+os.sep+lib_type+" install\n") out.close() def dumpEnvironment(ctx, includes, platform): conf=generateConfiguration(ctx, includes, platform) if platform in conf["platforms"]: p=conf["platforms"][platform] # print(str(p)) host="" if "host" in p: host="HOST=\""+p["host"]+"\" " sys.stdout.write("export CC=\""+p["cc"]+"\" "+ "export AR=\""+p["ar"]+"\" "+ "export LD=\""+p["ld"]+"\" " "export CPPFLAGS=\""+p["cppflags"]+"\" " "export CFLAGS=\""+p["cflags"]+"\" "+ host ) else: parseError("platform "+platform+" is unknown.") sys.stderr.write("available platforms:"); for platform in conf["platforms"]: sys.stderr.write(platform) def set_external_flag(ctx, lib, flag, value): # sys.stderr.write("SETTING "+lib+" "+flag+" "+str(value)+"\n") if lib in ctx["externals"]: ctx["externals"][lib][flag]=value else: ctx["externals"][lib]={flag: value} def is_external(ctx, lib): if lib in ctx["externals"]: if "external" in ctx["externals"][lib]: return ctx["externals"][lib]["external"] else: return False else: return False def generateZipPackage(ctx, source, lib_type, install_zip): zip=zipfile.ZipFile(install_zip, 'w', zipfile.ZIP_DEFLATED) base=os.path.splitext(install_zip)[0]+"/" platform=ctx["platforms"][0] conf=generateConfiguration(ctx, [source], platform) if platformSubseteqTest(ctx["platforms"][0], "win32-*-*"): obj_dir=os.path.join("win32", ctx["platform"].split('-')[1]) tool_ext=".exe" lib_exts=[".lib"] if (lib_type=="shared"): shared_exts.append(".dll") lib_prefix="" else: obj_dir=os.path.join("build", ctx["platform"], lib_type) tool_ext="" if lib_type=="shared": lib_exts=[".dylib"] else: lib_exts=[".a"] lib_prefix="lib" for lib in conf["libraries"]: if not lib["external"] and not isExcluded(conf, ctx, lib["name"]): for include in lib["header"]["files"]: if None!=include["install"]: target=base+"include/" if len(include["install"])>0: target=target+include["install"]+"/" target=target+os.path.split(include["path"])[1] zip.write(include["path"], target) for lib_ext in lib_exts: target=base+"lib/"+lib_prefix+lib["name"]+lib_ext # print "ADD "+os.path.join(obj_dir, lib_prefix+lib["name"]+lib_ext) zip.write(os.path.join(obj_dir, lib_prefix+lib["name"]+lib_ext), target) for tool in conf["tools"]: if not isExcluded(conf, ctx, tool["name"]): target=base+"bin/"+tool["name"]+tool_ext zip.write(os.path.join(obj_dir, tool["name"]+tool_ext), target) zip.write(os.path.join("third_party", "LICENSE"), base+"/LICENSE.THIRD_PARTY") zip.write("LICENSE", base+"/LICENSE") zip.close() def installFiles(ctx, source, lib_type, base): copy_ctx=None platform=ctx["platforms"][0] conf=generateConfiguration(ctx, [source], platform) if platformSubseteqTest(ctx["platforms"][0], "win32-*-*"): obj_dir=os.path.join("win32", ctx["platform"].split('-')[1]) tool_ext=".exe" lib_exts=[".lib"] lib_prefix="" else: obj_dir=os.path.join("build", ctx["platform"], lib_type) tool_ext="" lib_exts=[".a", getSharedExt(conf, ctx)] lib_prefix="lib" for lib in conf["libraries"]: if not lib["external"] and not isExcluded(conf, ctx, lib["name"]): for include in lib["header"]["files"]: if None!=include["install"]: target=base+"include/" if len(include["install"])>0: target=target+include["install"]+"/" target=target+os.path.split(include["path"])[1] copyFile(copy_ctx, include["path"], target) for lib_ext in lib_exts: target=base+"lib/"+lib_prefix+lib["name"]+lib_ext copyFile(copy_ctx, os.path.join(obj_dir, lib_prefix+lib["name"]+lib_ext), target) for tool in conf["tools"]: if not isExcluded(conf, ctx, tool["name"]): target=base+"bin/"+tool["name"]+tool_ext copyFile(copy_ctx, os.path.join(obj_dir, tool["name"]+tool_ext), target) copyFile(copy_ctx, os.path.join("third_party", "LICENSE"), base+"/LICENSE.THIRD_PARTY") copyFile(copy_ctx, "LICENSE", base+"/LICENSE") def usage(): print("usage:") print(" generate [--include \"Makefile.xml\"]") print(" [--config-dir \"config/\"]") print(" [--print-env \"linux-release-gcc\"]") print(" [--package \"xyz.zip/\"]") if __name__ == "__main__": try: opts, args = getopt.getopt(sys.argv[1:], "h", ["help", "include=", "config-dir=", "print-env=", "package=", "install=", "with-zlib-cppflags=", "with-zlib-ldflags=", "with-zlib=", "with-libxml-cppflags=", "with-libxml-ldflags=", "with-libxml=", "type="]) except getopt.GetoptError, err: # print help information and exit: print str(err) # will print something like "option -a not recognized" usage() sys.exit(2) ctx={ "base": os.path.abspath(os.curdir), "root": os.path.abspath(os.curdir), "platform": "?-?-?", "platforms": [], "externals": {} } ctx["config"]=ctx["base"] includes=[] dump_env=[] install_zip=None target_type="static" for o, a in opts: if o in ("-h", "--help"): usage() sys.exit(0) elif o in ("--include"): includes.append(a) elif o in ("--config-dir"): ctx["config"]=os.path.join(ctx["base"], a) elif o in ("--print-env"): args=[] dump_env=[a] elif o in ("--package"): install_zip=a elif o in ("--install"): install_files=a elif o in ("--with-zlib"): set_external_flag(ctx, "zlib", "external", "yes"==a) elif o in ("--with-zlib-cppflags"): set_external_flag(ctx, "zlib", "cppflags", a) elif o in ("--with-zlib-ldflags"): set_external_flag(ctx, "zlib", "ldflags", a) elif o in ("--with-libxml"): set_external_flag(ctx, "xml", "external", "yes"==a) elif o in ("--with-libxml-cppflags"): set_external_flag(ctx, "xml", "cppflags", a) elif o in ("--with-libxml-ldflags"): set_external_flag(ctx, "xml", "ldflags", a) elif o in ("--type"): target_type=a for platform in args: ctx["platforms"].append(platform) if 1==len(ctx["platforms"]) and None!=install_zip and 1==len(includes): ctx["root"]=os.path.abspath(os.path.split(includes[0])[0]) generateZipPackage(ctx, includes[0], target_type, install_zip) elif 1==len(ctx["platforms"]) and platformSubseteqTest(ctx["platforms"][0], "win32-*-msvc-*") and 1==len(includes): ctx["root"]=os.path.abspath(os.path.split(includes[0])[0]) generateWin32(ctx, includes[0]) else: if is_external(ctx, "zlib") and is_external(ctx, "xml"): lib_types=["static", "shared"] else: lib_types=["static"] if not os.path.exists("build"): os.makedirs("build") f=open(os.path.join("build", "configure.ctx"), "w") f.write(str(ctx)) f.close() for include in includes: ctx["root"]=os.path.abspath(os.path.split(include)[0]) generateTypedMakefiles(ctx, include, lib_types) for platform in dump_env: dumpEnvironment(ctx, includes, platform)