comparison mx.graal/mx_graal_makefile.py @ 22017:66dd063eb6a0

renamed mx/ to mx.graal/ in preparation for working with mxtool2
author Doug Simon <doug.simon@oracle.com>
date Wed, 17 Jun 2015 13:56:55 +0200
parents mx/mx_graal_makefile.py@72129dd49bc0
children 0e095e2c24e2
comparison
equal deleted inserted replaced
22016:f2cf8824040b 22017:66dd063eb6a0
1 #
2 # ----------------------------------------------------------------------------------------------------
3 #
4 # Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
5 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 #
7 # This code is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License version 2 only, as
9 # published by the Free Software Foundation.
10 #
11 # This code is distributed in the hope that it will be useful, but WITHOUT
12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 # version 2 for more details (a copy is included in the LICENSE file that
15 # accompanied this code).
16 #
17 # You should have received a copy of the GNU General Public License version
18 # 2 along with this work; if not, write to the Free Software Foundation,
19 # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 #
21 # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 # or visit www.oracle.com if you need additional information or have any
23 # questions.
24 #
25 # ----------------------------------------------------------------------------------------------------
26 #
27 import mx, mx_graal, 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
45
46 def build_makefile(args):
47 """Creates a Makefile which is able to build distributions without mx
48
49 The return value indicates how many files were modified"""
50 parser = ArgumentParser(prog='mx makefile')
51 parser.add_argument('-o', action='store', dest='output', help='Write contents to this file.')
52 parser.add_argument('selectedDists', help="Selected distribution names which are going to be built with make.", nargs=REMAINDER)
53 opts = parser.parse_args(args)
54
55 if opts.selectedDists == None or len(opts.selectedDists) == 0:
56 opts.selectedDists = [d.name for d in mx_graal._jdkDeployedDists if d.partOfHotSpot]
57 mf = Makefile()
58 commandline = " ".join(["mx.sh", "makefile"] + args)
59 if do_build_makefile(mf, opts.selectedDists, commandline):
60 contents = mf.generate()
61 if opts.output == None:
62 print contents
63 else:
64 if mx.update_file(opts.output, contents, showDiff=True):
65 return 1
66 return 0
67
68 def short_dist_name(name):
69 return name.replace("COM_ORACLE_", "")
70
71 def filter_projects(deps, t):
72 def typeFilter(project): # filters
73 if isinstance(project, str):
74 project = mx.dependency(project, True)
75 return isinstance(project, t)
76 return [d for d in deps if typeFilter(d)]
77
78 def get_jdk_deployed_dists():
79 return [d.name for d in mx_graal._jdkDeployedDists]
80
81 def update_list(li, elements):
82 for e in elements:
83 if e not in li:
84 li.append(e)
85
86 def make_dist_rule(dist, mf):
87 def path_dist_relative(p):
88 return os.path.relpath(p, dist.suite.dir)
89 shortName = short_dist_name(dist.name)
90 jdkDeployedDists = get_jdk_deployed_dists()
91 jarPath = path_dist_relative(dist.path)
92 sourcesVariableName = shortName + "_SRC"
93 depJarVariableName = shortName + "_DEP_JARS"
94 sources = []
95 resources = []
96 sortedDeps = dist.sorted_deps(True, transitive=False, includeAnnotationProcessors=True)
97 projects = filter_projects(sortedDeps, mx.Project)
98 targetPathPrefix = "$(TARGET)" + os.path.sep
99 libraryDeps = [path_dist_relative(l.get_path(False)) for l in filter_projects(sortedDeps, mx.Library)]
100
101 annotationProcessorDeps = []
102 distDeps = dist.get_dist_deps(includeSelf=False, transitive=True)
103 distDepProjects = []
104 for d in distDeps:
105 update_list(distDepProjects, d.sorted_deps(includeLibs=False, transitive=True))
106
107 classPath = [targetPathPrefix + path_dist_relative(d.path) for d in distDeps] + libraryDeps \
108 + [path_dist_relative(mx.dependency(name).path) for name in dist.excludedDependencies]
109 for p in projects:
110 if p.definedAnnotationProcessors != None and p.definedAnnotationProcessorsDist != dist:
111 update_list(annotationProcessorDeps, [p])
112 for p in projects:
113 projectDir = path_dist_relative(p.dir)
114 if p not in distDepProjects and p not in annotationProcessorDeps:
115 for src in [projectDir + os.path.sep + d for d in p.srcDirs]:
116 sources.append("$(shell find {} -type f 2> /dev/null)".format(src))
117 metaInf = src + os.path.sep + "META-INF"
118 if os.path.exists(metaInf):
119 resources.append(metaInf)
120
121
122 sourceLines = sourcesVariableName + " = " + ("\n" + sourcesVariableName + " += ").join(sources)
123 apPaths = []
124 apDistNames = []
125 apDistVariableNames = []
126 for p in annotationProcessorDeps:
127 apPaths.append(path_dist_relative(p.definedAnnotationProcessorsDist.path))
128 name = short_dist_name(p.definedAnnotationProcessorsDist.name)
129 apDistNames.append(name)
130 apDistVariableNames.append("$(" + name + "_JAR)")
131 shouldExport = dist.name in jdkDeployedDists
132 props = {
133 "name": shortName,
134 "jarPath": targetPathPrefix + jarPath,
135 "depJarsVariableAccess": "$(" + depJarVariableName + ")" if len(classPath) > 0 else "",
136 "depJarsVariable": depJarVariableName,
137 "sourceLines": sourceLines,
138 "sourcesVariableName": sourcesVariableName,
139 "annotationProcessors": " ".join(apDistVariableNames),
140 "cpAnnotationProcessors": ":".join(apDistVariableNames),
141 "jarDeps": " ".join(classPath),
142 "copyResources": " ".join(resources)
143 }
144
145 mf.add_definition(sourceLines)
146 mf.add_definition("{name}_JAR = {jarPath}".format(**props))
147 if len(classPath) > 0: mf.add_definition("{depJarsVariable} = {jarDeps}".format(**props))
148 if shouldExport: mf.add_definition("EXPORTED_FILES += $({name}_JAR)".format(**props))
149 mf.add_rule("""$({name}_JAR): $({sourcesVariableName}) {annotationProcessors} {depJarsVariableAccess}
150 \t$(call build_and_jar,{cpAnnotationProcessors},$(subst $(space),:,{depJarsVariableAccess}),{copyResources},$({name}_JAR))
151 """.format(**props))
152 return
153
154
155
156 def do_build_makefile(mf, selectedDists, commandline):
157 java = mx.java()
158 bootClassPath = java.bootclasspath()
159 bootClassPath = bootClassPath.replace(os.path.realpath(java.jdk), "$(ABS_BOOTDIR)")
160 jdkBootClassPathVariableName = "JDK_BOOTCLASSPATH"
161
162 mf.add_definition("""# This Makefile is generated automatically, do not edit
163
164 TARGET=.
165 # Bootstrap JDK to be used (for javac and jar)
166 ABS_BOOTDIR=
167
168 JAVAC=$(ABS_BOOTDIR)/bin/javac -g -target """ + str(java.javaCompliance) + """
169 JAR=$(ABS_BOOTDIR)/bin/jar
170
171 HS_COMMON_SRC=.
172
173 # Directories, where the generated property-files reside within the JAR files
174 PROVIDERS_INF=/META-INF/jvmci.providers
175 SERVICES_INF=/META-INF/jvmci.services
176 OPTIONS_INF=/META-INF/jvmci.options
177
178 JARS = $(foreach dist,$(DISTRIBUTIONS),$($(dist)_JAR))
179
180 ifeq ($(ABS_BOOTDIR),)
181 $(error Variable ABS_BOOTDIR must be set to a JDK installation.)
182 endif
183 ifeq ($(MAKE_VERBOSE),)
184 QUIETLY=@
185 endif
186
187 # Required to construct a whitespace for use with subst
188 space :=
189 space +=
190
191 # Takes the provider files created by ServiceProviderProcessor (the processor
192 # for the @ServiceProvider annotation) and merges them into a single file.
193 # Arguments:
194 # 1: directory with contents of the JAR file
195 define process_providers
196 $(eval providers := $(1)/$(PROVIDERS_INF))
197 $(eval services := $(1)/$(SERVICES_INF))
198 $(QUIETLY) test -d $(services) || mkdir -p $(services)
199 $(QUIETLY) test ! -d $(providers) || (cd $(providers) && for i in $$(ls); do c=$$(cat $$i); echo $$i >> $(abspath $(services))/$$c; rm $$i; done)
200
201 @# Since all projects are built together with one javac call we cannot determine
202 @# which project contains HotSpotVMConfig.inline.hpp so we hardcode it.
203 $(eval vmconfig := $(1)/hotspot/HotSpotVMConfig.inline.hpp)
204 $(eval vmconfigDest := $(HS_COMMON_SRC)/../jvmci/com.oracle.jvmci.hotspot/src_gen/hotspot)
205 $(QUIETLY) test ! -f $(vmconfig) || (mkdir -p $(vmconfigDest) && cp $(vmconfig) $(vmconfigDest))
206 endef
207
208 # Reads the files in jvmci.options/ created by OptionProcessor (the processor for the @Option annotation)
209 # and appends to services/com.oracle.jvmci.options.Options entries for the providers
210 # also created by the same processor.
211 # Arguments:
212 # 1: directory with contents of the JAR file
213 define process_options
214 $(eval options := $(1)/$(OPTIONS_INF))
215 $(eval services := $(1)/META-INF/services)
216 $(QUIETLY) test -d $(services) || mkdir -p $(services)
217 $(QUIETLY) test ! -d $(options) || (cd $(options) && for i in $$(ls); do echo $${i}_Options >> $(abspath $(services))/com.oracle.jvmci.options.Options; done)
218 endef
219
220 # Extracts META-INF/jvmci.services and META-INF/jvmci.options of a JAR file into a given directory
221 # Arguments:
222 # 1: JAR file to extract
223 # 2: target directory (which already exists)
224 define extract
225 $(eval TMP := $(shell mktemp -d $(TARGET)/tmp_XXXXX))
226 $(QUIETLY) cd $(TMP) && $(JAR) xf $(abspath $(1)) && \\
227 ((test ! -d .$(SERVICES_INF) || cp -r .$(SERVICES_INF) $(abspath $(2))) && \\
228 (test ! -d .$(OPTIONS_INF) || cp -r .$(OPTIONS_INF) $(abspath $(2))));
229 $(QUIETLY) rm -r $(TMP);
230 $(QUIETLY) cp $(1) $(2)
231 endef
232
233 # Calls $(JAVAC) with the boot class path $(JDK_BOOTCLASSPATH) and sources taken from the automatic variable $^
234 # Arguments:
235 # 1: processorpath
236 # 2: classpath
237 # 3: resources to copy
238 # 4: target JAR file
239 define build_and_jar
240 $(info Building $(4))
241 $(eval TMP := $(shell mkdir -p $(TARGET) && mktemp -d $(TARGET)/tmp_XXXXX))
242 $(QUIETLY) $(JAVAC) -d $(TMP) -processorpath :$(1) -bootclasspath $(JDK_BOOTCLASSPATH) -cp :$(2) $(filter %.java,$^)
243 $(QUIETLY) test "$(3)" = "" || cp -r $(3) $(TMP)
244 $(QUIETLY) $(call process_options,$(TMP))
245 $(QUIETLY) $(call process_providers,$(TMP))
246 $(QUIETLY) mkdir -p $(shell dirname $(4))
247 $(QUIETLY) $(JAR) -0cf $(4) -C $(TMP) .
248 $(QUIETLY) rm -r $(TMP)
249 endef
250
251 # Verifies that make/defs.make contains an appropriate line for each JVMCI service or option
252 # and that only existing JVMCI services and options are exported.
253 # Arguments:
254 # 1: list of service or option files
255 # 2: variable name for directory of service or option files
256 define verify_defs_make
257 $(eval defs := make/defs.make)
258 $(eval uncondPattern := EXPORT_LIST += $$$$($(2))/)
259 $(eval condPattern := CONDITIONAL_EXPORT_LIST += $$$$($(2))/)
260 $(eval unconditionalExports := $(shell grep '^EXPORT_LIST += $$($2)' make/defs.make | sed 's:.*($(2))/::g'))
261 $(eval conditionalExports := $(shell grep '^CONDITIONAL_EXPORT_LIST += $$($2)' make/defs.make | sed 's:.*($(2))/::g'))
262 $(eval allExports := $(unconditionalExports) $(conditionalExports))
263 $(foreach file,$(1),$(if $(findstring $(file),$(allExports)), ,$(error "Line matching '$(uncondPattern)$(file)' or '$(condPattern)$(file)' not found in $(defs)")))
264 $(foreach export,$(unconditionalExports),$(if $(findstring $(export),$(1)), ,$(error "The line '$(uncondPattern)$(export)' should not be in $(defs)")))
265 endef
266
267 all: default
268 \t$(info Put $(EXPORTED_FILES) into SHARED_DIR $(SHARED_DIR))
269 \t$(shell mkdir -p $(SHARED_DIR))
270 \t$(foreach export,$(EXPORTED_FILES),$(call extract,$(export),$(SHARED_DIR)))
271
272 export: all
273 \t$(call verify_defs_make,$(notdir $(wildcard $(SHARED_DIR)/jvmci.services/*)),EXPORT_JRE_LIB_JVMCI_SERVICES_DIR)
274 \t$(call verify_defs_make,$(notdir $(wildcard $(SHARED_DIR)/jvmci.options/*)),EXPORT_JRE_LIB_JVMCI_OPTIONS_DIR)
275 .PHONY: export
276
277 clean:
278 \t$(QUIETLY) rm $(JARS) 2> /dev/null || true
279 \t$(QUIETLY) rmdir -p $(dir $(JARS)) 2> /dev/null || true
280 .PHONY: export clean
281
282 """)
283 s = mx.suite("graal")
284 dists = []
285 ap = []
286 projects = []
287 for d in s.dists:
288 if d.name in selectedDists:
289 update_list(dists, d.get_dist_deps(True, True))
290 update_list(projects, d.sorted_deps(includeLibs=False, transitive=True))
291
292 for p in projects:
293 deps = p.all_deps([], False, includeSelf=True, includeJreLibs=False, includeAnnotationProcessors=True)
294 for d in deps:
295 if d.definedAnnotationProcessorsDist != None:
296 apd = d.definedAnnotationProcessorsDist
297 update_list(ap, [apd])
298
299 if len(dists) > 0:
300 mf.add_definition(jdkBootClassPathVariableName + " = " + bootClassPath)
301 for d in ap: make_dist_rule(d, mf)
302 for d in dists: make_dist_rule(d, mf)
303 mf.add_definition("DISTRIBUTIONS = " + " ".join([short_dist_name(d.name) for d in dists+ap]))
304 mf.add_rule("default: $({}_JAR)\n.PHONY: default\n".format("_JAR) $(".join([short_dist_name(d.name) for d in dists])))
305 return True
306 else:
307 for d in dists:
308 selectedDists.remove(d.name)
309 print "Distribution(s) '" + "', '".join(selectedDists) + "' does not exist."