comparison mx/mx_graal_makefile.py @ 21717:a3315bce5192

Change makefile generator to produce human readable code (JBS:GRAAL-52)
author Stefan Anzinger <stefan.anzinger@oracle.com>
date Wed, 03 Jun 2015 20:24:04 +0200
parents 93d486d51ab4
children b5bbf03bc17a
comparison
equal deleted inserted replaced
21716:2f9e4d984d16 21717:a3315bce5192
1 import mx, os, sys
2 # 1 #
3 # ---------------------------------------------------------------------------------------------------- 2 # ----------------------------------------------------------------------------------------------------
4 # 3 #
5 # Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. 4 # Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
6 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
23 # or visit www.oracle.com if you need additional information or have any 22 # or visit www.oracle.com if you need additional information or have any
24 # questions. 23 # questions.
25 # 24 #
26 # ---------------------------------------------------------------------------------------------------- 25 # ----------------------------------------------------------------------------------------------------
27 # 26 #
28 27 import mx, os
28 from argparse import ArgumentParser, REMAINDER
29
30
31 class Makefile:
32 def __init__(self):
33 self.rules = []
34 self.definitions = []
35
36 def add_rule(self, s):
37 self.rules.append(s)
38
39 def add_definition(self, s):
40 self.definitions.append(s)
41
42 def generate(self):
43 return "\n\n".join(self.definitions + self.rules)
44
29 45
30 def build_makefile(args): 46 def build_makefile(args):
31 """Build a Makefile from the suitte.py to build graa.jar without python""" 47 """Creates a Makefile which is able to build distributions without mx"""
32 if len(args) == 0 or args[0] == "-": 48 parser = ArgumentParser(prog='mx makefile')
33 do_build_makefile(lambda l: sys.stdout.write(l + os.linesep)) 49 parser.add_argument('-o', action='store', dest='output', help='Write contents to this file.')
34 elif args[0] == "-o": 50 parser.add_argument('selectedDists', help="Selected distribution names which are going to be built with make.", nargs=REMAINDER)
35 with open(args[1], "w") as f: 51 args = parser.parse_args(args)
36 do_build_makefile(lambda l: f.write(l + os.linesep)) 52
37 53 if args.selectedDists == None or len(args.selectedDists) == 0:
38 def relative_dep_path(d): 54 parser.print_help()
39 if isinstance(d, str): d = mx.dependency(d) 55 return
40 return os.path.basename(d.get_path(False)) 56 mf = Makefile()
41 57 if do_build_makefile(mf, args.selectedDists):
42 def createMakeRule(p, bootClasspath): 58 contents = mf.generate()
43 def filterDeps(deps, t): 59 if args.output == None:
44 def typeFilter(project): # filters 60 print contents
45 if isinstance(project, str): 61 else:
46 project = mx.dependency(project, True) 62 with open(args.output, "w") as f:
47 return isinstance(project, t) 63 f.write(contents)
48 return [d for d in deps if typeFilter(d)] 64
49 65
50 66 def filter_projects(deps, t):
51 canonicalDeps = p.canonical_deps() 67 def typeFilter(project): # filters
52 canonicalProjectDep = filterDeps(canonicalDeps, mx.Project) 68 if isinstance(project, str):
53 canonicalProjectDepDirs = ['$(TARGET)/' +i for i in canonicalProjectDep] 69 project = mx.dependency(project, True)
54 canonicalLibDep = filterDeps(canonicalDeps, mx.Library) 70 return isinstance(project, t)
55 canonicalLibDepJars = ["$(LIB)/" + relative_dep_path(d) for d in canonicalLibDep] 71 return [d for d in deps if typeFilter(d)]
56 72
57 allDep = p.all_deps([], True, False, includeAnnotationProcessors=True) 73
58 allProcessorDistNames = [x.definedAnnotationProcessorsDist.name for x in filterDeps(allDep, mx.Project) if x.definedAnnotationProcessors != None] 74 def make_dist_rule(dist, mf, bootClassPath=None):
59 allProjectDep = filterDeps(allDep, mx.Project) 75 def path_dist_relative(p):
60 allProjectDepDir = ['$(TARGET)/' +i.name for i in allProjectDep] 76 return os.path.relpath(p, dist.suite.dir)
61 allLibDep = filterDeps(allDep, mx.Library) 77 jarPath = path_dist_relative(dist.path)
62 allLibDepJar = ["$(LIB)/" + relative_dep_path(d) for d in allLibDep] 78 sourcesVariableName = dist.name + "_SRC"
63 79 depJarVariableName = dist.name + "_DEP_JARS";
64 processor = p.annotation_processors_path() 80 sources = []
65 if processor != None: processor = processor.replace(p.suite.dir, "$(TARGET)") 81 resources = []
66 82 sortedDeps = dist.sorted_deps(True, transitive=False, includeAnnotationProcessors=True)
67 cp = allLibDepJar +allProjectDepDir 83 projects = filter_projects(sortedDeps, mx.Project)
84 targetPathPrefix = "$(TARGET)" + os.path.sep
85 libraryDeps = [path_dist_relative(l.get_path(False)) for l in filter_projects(sortedDeps, mx.Library)]
86
87 annotationProcessorDeps = set()
88 distDeps = dist.get_dist_deps(includeSelf=False, transitive=True)
89 distDepProjects = set()
90 for d in distDeps:
91 distDepProjects.update(d.sorted_deps(includeLibs=False, transitive=True))
92 classPath = [targetPathPrefix + path_dist_relative(d.path) for d in distDeps] + libraryDeps
93
94 for p in projects:
95 if p.definedAnnotationProcessors != None and p.definedAnnotationProcessorsDist != dist:
96 annotationProcessorDeps.add(p)
97 for p in projects:
98 projectDir = path_dist_relative(p.dir)
99 if p not in distDepProjects and p not in annotationProcessorDeps:
100 generatedSource = [path_dist_relative(p.source_gen_dir())] if len(annotationProcessorDeps) > 0 else []
101
102 for d in p.srcDirs + generatedSource:
103 src = projectDir + os.path.sep + d
104 sources.append("$(shell find {} -type file -name *.java 2> /dev/null)".format(src))
105 metaInf = src + os.path.sep + "META-INF";
106 if os.path.exists(metaInf):
107 resources.append(metaInf)
108
109
110 sourceLines = sourcesVariableName + " = " + ("\n" + sourcesVariableName + " += ").join(sources)
111 annotationProcessorPaths = []
112 annotationProcessorDistNames = []
113 annotationProcessorDistVariableNames = []
114 for p in annotationProcessorDeps:
115 annotationProcessorPaths.append(path_dist_relative(p.definedAnnotationProcessorsDist.path))
116 name = p.definedAnnotationProcessorsDist.name
117 annotationProcessorDistNames.append(name)
118 annotationProcessorDistVariableNames.append("$(" + name + "_JAR)")
119
68 props = { 120 props = {
69 'name': p.name, 121 "name": dist.name,
70 'project_deps': ' '.join(canonicalProjectDepDirs + canonicalLibDepJars + allProcessorDistNames), 122 "jarPath": targetPathPrefix + jarPath,
71 'cp_deps': ('-cp ' + ':'.join(cp)) if len(cp) > 0 else '', 123 "depends": "",
72 'cp_boot': ('-bootclasspath ' + bootClasspath) if len(bootClasspath) > 0 else '', 124 "depJarsVariableAccess": "$(" + depJarVariableName + ")" if len(classPath) > 0 else "",
73 'processor': ('-processorpath ' + processor) if processor != None else '' 125 "depJarsVariable": depJarVariableName,
74 } 126 "sourceLines": sourceLines,
75 return """$(TARGET)/{name}: $(shell find graal/{name}/src/ -type f -name *.java) {project_deps} 127 "sourcesVariableName": sourcesVariableName,
128 "annotationProcessors": " ".join(annotationProcessorDistVariableNames),
129 "cpAnnotationProcessors": "-processorpath " + ":".join(annotationProcessorDistVariableNames) if len(annotationProcessorDistVariableNames) > 0 else "",
130 "bootCp": ("-bootclasspath " + bootClassPath) if bootClassPath != None else "",
131 "cpDeps": ("-cp " + ":".join(classPath)) if len(classPath) > 0 else "",
132 "jarDeps": " ".join(classPath),
133 "copyResources": "cp -r {} $(TMP)".format(" ".join(resources)) if len(resources) > 0 else "",
134 "targetPathPrefix": targetPathPrefix
135 }
136
137 mf.add_definition(sourceLines)
138 mf.add_definition("{name}_JAR = {jarPath}".format(**props))
139 if len(classPath) > 0: mf.add_definition("{depJarsVariable} = {jarDeps}".format(**props))
140 mf.add_rule("""$({name}_JAR): $({sourcesVariableName}) {annotationProcessors} {depJarsVariableAccess} $(TARGET)/build
76 \t$(eval TMP := $(shell mktemp -d)) 141 \t$(eval TMP := $(shell mktemp -d))
77 \ttest ! -d $(TARGET)/{name} || cp -Rp $(TARGET)/{name} $(TMP) 142 \t$(JAVAC) -d $(TMP) {cpAnnotationProcessors} {bootCp} {cpDeps} $({sourcesVariableName})
78 \t$(JAVAC) -d $(TMP) {cp_boot} {processor} {cp_deps} $(shell find graal/{name}/src/ -type f -name *.java) 143 \t{copyResources}
79 \ttest ! -d graal/{name}/src/META-INF || (mkdir -p $(TARGET)/{name}/META-INF/ && cp -r graal/{name}/src/META-INF/ $(TARGET)/{name}/) 144 \t$(call process_options,$(TMP))
80 \tmkdir -p $(TARGET)/{name} 145 \tmkdir -p $$(dirname $({name}_JAR))
81 \tcp -r $(TMP)/* $(TARGET)/{name} 146 \t$(JAR) cf $({name}_JAR) -C $(TMP) .
82 \ttouch $(TARGET)/{name} 147 \trm -r $(TMP)""".format(**props))
83 \trm -r $(TMP) 148 return
84 """.format(**props) 149
85 150
86 def createDistributionRule(dist): 151 def do_build_makefile(mf, selectedDists):
87 sorted_deps = set(dist.sorted_deps(False, True)) 152 java = mx.java()
88 depDirs = ' '.join(['$(TARGET)/' + i.name for i in sorted_deps]) 153 bootClassPath = java.bootclasspath()
89 depDirsStar = ' '.join(['$(TARGET)/' + i.name + '/*' for i in sorted_deps]) 154 bootClassPath = bootClassPath.replace(java.jdk, "$(JDK)")
90 jarPath = os.path.relpath(dist.path, dist.suite.dir) 155 jdkBootClassPathVariableName = "JDK_BOOTCLASSPATH"
91 jarDir = os.path.dirname(jarPath) 156
92 props = { 157 mf.add_definition("""VERBOSE=
93 'dist_name': dist.name, 158 TARGET=.
94 'depDirs': depDirs,
95 'depDirsStar': depDirsStar,
96 'jar_path': jarPath,
97 'jar_dir': jarDir,
98 'providers_dir': '$(TMP)/META-INF/providers/ ',
99 'services_dir': '$(TMP)/META-INF/services/'
100 }
101 return """{dist_name}: {depDirs}
102 \t$(eval TMP := $(shell mktemp -d))
103 \tmkdir -p $(TARGET){jar_dir}
104 \ttouch $(TARGET)/{jar_path}
105 \tcp -r {depDirsStar} $(TMP)
106 \ttest -d {services_dir} || mkdir -p {services_dir}
107 \ttest ! -d {providers_dir} || (cd {providers_dir} && for i in $$(ls); do c=$$(cat $$i); echo $$i >> {services_dir}$$c; done)
108 \ttest ! -d {providers_dir} || rm -r {providers_dir}
109 \t$(JAR) cvf $(TARGET){jar_path} -C $(TMP) .
110 \trm -r $(TMP)
111 """.format(**props)
112
113 def createDownloadRule(lib):
114 http_urls = [u for u in lib.urls if u.startswith("http")]
115 if len(http_urls) == 0: http_urls = [u for u in lib.urls if u.startswith("jar")]
116 if len(http_urls) == 0: raise BaseException("No http url specified for downloading library %s: available urls: %s" % (lib.name, lib.urls))
117 url = http_urls[0]
118 tofile = '$(LIB)/' + relative_dep_path(lib)
119 if url.startswith("jar"):
120 props = {
121 'url': url[url.find(":")+1:url.rfind("!")],
122 'archive_file': url[url.rfind("!")+1:],
123 'dest': tofile
124 }
125 dl = """\t$(eval TMP := $(shell mktemp -d))
126 \tcd $(TMP) && $(WGET) -O dl.zip {url} && $(JAR) xf dl.zip
127 \tmv $(TMP)/{archive_file} {dest}
128 \trm -rf $(TMP)""".format(**props)
129 else:
130 dl = "\t$(WGET) -O {} {}".format(tofile, url)
131 return """{}:\n{}""".format(tofile, dl)
132
133
134 def create_suite_build(suite, out):
135 for p in suite.projects:
136 java = mx.java(p.javaCompliance)
137 bootClassPath = java.bootclasspath()
138 bootClassPath = bootClassPath.replace(java.jdk, "$(JDK)")
139 out(createMakeRule(p, bootClassPath))
140 for l in suite.libs:
141 out(createDownloadRule(l))
142
143 distributionNames = []
144 for d in suite.dists:
145 distributionNames.append(d.name)
146 out(createDistributionRule(d))
147 out("{0}: {1}\n.PHONY: {1}".format(suite.name, " ".join(distributionNames)))
148
149
150 def do_build_makefile(out):
151 out("""VERBOSE=
152 TARGET=build/
153 LIB=$(TARGET)/lib
154 JDK= 159 JDK=
155 160
156 WGET=wget 161 WGET=wget
157 JAVAC=$(JDK)/bin/javac 162 JAVAC=$(JDK)/bin/javac -g -target """ + str(java.javaCompliance) + """
158 JAR=$(JDK)/bin/jar 163 JAR=$(JDK)/bin/jar
159 164
160 165
161 ifeq ($(JDK),) 166 ifeq ($(JDK),)
162 $(error Variable JDK must be set to a JDK installation.) 167 $(error Variable JDK must be set to a JDK installation.)
163 endif 168 endif
164 ifneq ($(VERBOSE),) 169 ifneq ($(VERBOSE),)
165 SHELL=sh -x 170 SHELL=sh -x
166 endif 171 endif
167 172
173 define process_options =
174 $(eval providers=$(1)/META-INF/providers/)
175 $(eval services=$(1)/META-INF/services/)
176 test -d $(services) || mkdir -p $(services)
177 test ! -d $(providers) || (cd $(providers) && for i in $$(ls $(providers)); do c=$$(cat $$i); echo $$i >> $(services)$$c; rm $$i; done)
178 endef
179
168 all: default 180 all: default
169 181
170 $(TARGET): 182 $(TARGET)/build:
171 \tmkdir -p $(TARGET) 183 \tmkdir -p $(TARGET)/build
172 184
173 $(LIB): 185 $(LIB):
174 \tmkdir -p $(LIB) 186 \tmkdir -p $(LIB)
175 """) 187 """)
176 suiteNames = [] 188 s = mx.suite("graal")
177 for s in mx.suites(): 189 dists = set()
178 suiteNames.append(s.name) 190 ap = set()
179 create_suite_build(s, out) 191 projects = set()
180 192
181 out("""default: $(TARGET) $(LIB) {0} 193 for d in s.dists:
182 .PHONY: {0} 194 if d.name in selectedDists:
183 """.format(" ".join(suiteNames))) 195 dists.update(d.get_dist_deps(True, True))
184 196 projects.update(d.sorted_deps(includeLibs=False, transitive=True))
197 for p in projects:
198 deps = p.all_deps([], False, includeSelf=True, includeJreLibs=False, includeAnnotationProcessors=True)
199 for d in deps:
200 if d.definedAnnotationProcessorsDist != None:
201 apd = d.definedAnnotationProcessorsDist
202 ap.add(apd)
203
204 if len(dists) > 0:
205 mf.add_definition(jdkBootClassPathVariableName + " = " + bootClassPath)
206 bootClassPathVarAccess = "$(" + jdkBootClassPathVariableName + ")"
207 for d in ap: make_dist_rule(d, mf, bootClassPathVarAccess)
208 for d in dists: make_dist_rule(d, mf, bootClassPathVarAccess)
209 mf.add_rule("default: $({}_JAR)\n.PHONY: default".format("_JAR) $(".join([d.name for d in dists])))
210 return True
211 else:
212 for d in dists:
213 selectedDists.remove(d.name)
214 print "Distribution(s) '" + "', '".join(selectedDists) + "' does not exist."
215
216
217
218
219