1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 from __future__
import absolute_import
, print_function
, unicode_literals
18 from collections
.abc
import Iterable
20 from collections
import Iterable
23 base_dir
= os
.path
.abspath(os
.path
.dirname(__file__
))
24 sys
.path
.insert(0, os
.path
.join(base_dir
, "python", "mozboot"))
25 sys
.path
.insert(0, os
.path
.join(base_dir
, "python", "mozbuild"))
26 sys
.path
.insert(0, os
.path
.join(base_dir
, "third_party", "python", "six"))
27 from mozbuild
.configure
import (
31 from mozbuild
.pythonutil
import iter_modules_in_path
32 from mozbuild
.backend
.configenvironment
import PartialConfigEnvironment
33 from mozbuild
.util
import write_indented_repr
34 import mozpack
.path
as mozpath
41 if "OLD_CONFIGURE" not in os
.environ
:
42 os
.environ
["OLD_CONFIGURE"] = os
.path
.join(base_dir
, "old-configure")
44 sandbox
= ConfigureSandbox(config
, os
.environ
, argv
)
46 clobber_file
= "CLOBBER"
47 if not os
.path
.exists(clobber_file
):
48 # Simply touch the file.
49 with
open(clobber_file
, "a"):
52 if os
.environ
.get("MOZ_CONFIGURE_TRACE"):
53 sandbox
._logger
.setLevel(TRACE
)
55 sandbox
.run(os
.path
.join(os
.path
.dirname(__file__
), "moz.configure"))
60 logging
.getLogger("moz.configure").info("Creating config.status")
62 old_js_configure_substs
= config
.pop("OLD_JS_CONFIGURE_SUBSTS", None)
63 old_js_configure_defines
= config
.pop("OLD_JS_CONFIGURE_DEFINES", None)
64 if old_js_configure_substs
or old_js_configure_defines
:
65 js_config
= config
.copy()
71 if e
.errno
!= errno
.EEXIST
:
75 js_config
["OLD_CONFIGURE_SUBSTS"] = old_js_configure_substs
76 js_config
["OLD_CONFIGURE_DEFINES"] = old_js_configure_defines
77 # The build system frontend expects $objdir/js/src/config.status
78 # to have $objdir/js/src as topobjdir.
79 # We want forward slashes on all platforms.
80 js_config
["TOPOBJDIR"] += "/js/src"
81 config_status(js_config
, execute
=False)
85 return config_status(config
)
88 def check_unicode(obj
):
89 """Recursively check that all strings in the object are unicode strings."""
90 if isinstance(obj
, dict):
92 for k
, v
in six
.iteritems(obj
):
93 if not check_unicode(k
):
94 print("%s key is not unicode." % k
, file=sys
.stderr
)
96 elif not check_unicode(v
):
97 print("%s value is not unicode." % k
, file=sys
.stderr
)
100 if isinstance(obj
, bytes
):
102 if isinstance(obj
, six
.text_type
):
104 if isinstance(obj
, Iterable
):
105 return all(check_unicode(o
) for o
in obj
)
109 def config_status(config
, execute
=True):
110 # Sanitize config data to feed config.status
111 # Ideally, all the backend and frontend code would handle the booleans, but
112 # there are so many things involved, that it's easier to keep config.status
114 def sanitize_config(v
):
119 # Serialize types that look like lists and tuples as lists.
120 if not isinstance(v
, (bytes
, six
.text_type
, dict)) and isinstance(v
, Iterable
):
124 sanitized_config
= {}
125 sanitized_config
["substs"] = {
126 k
: sanitize_config(v
)
127 for k
, v
in six
.iteritems(config
)
133 "CONFIG_STATUS_DEPS",
134 "OLD_CONFIGURE_SUBSTS",
135 "OLD_CONFIGURE_DEFINES",
138 for k
, v
in config
["OLD_CONFIGURE_SUBSTS"]:
139 sanitized_config
["substs"][k
] = sanitize_config(v
)
140 sanitized_config
["defines"] = {
141 k
: sanitize_config(v
) for k
, v
in six
.iteritems(config
["DEFINES"])
143 for k
, v
in config
["OLD_CONFIGURE_DEFINES"]:
144 sanitized_config
["defines"][k
] = sanitize_config(v
)
145 sanitized_config
["topsrcdir"] = config
["TOPSRCDIR"]
146 sanitized_config
["topobjdir"] = config
["TOPOBJDIR"]
147 sanitized_config
["mozconfig"] = config
.get("MOZCONFIG")
149 if not check_unicode(sanitized_config
):
150 print("Configuration should be all unicode.", file=sys
.stderr
)
151 print("Please file a bug for the above.", file=sys
.stderr
)
154 # Some values in sanitized_config also have more complex types, such as
155 # EnumString, which using when calling config_status would currently
156 # break the build, as well as making it inconsistent with re-running
157 # config.status, for which they are normalized to plain strings via
158 # indented_repr. Likewise for non-dict non-string iterables being
159 # converted to lists.
161 if isinstance(obj
, dict):
162 return {k
: normalize(v
) for k
, v
in six
.iteritems(obj
)}
163 if isinstance(obj
, six
.text_type
):
164 return six
.text_type(obj
)
165 if isinstance(obj
, Iterable
):
166 return [normalize(o
) for o
in obj
]
169 sanitized_config
= normalize(sanitized_config
)
171 # Create config.status. Eventually, we'll want to just do the work it does
172 # here, when we're able to skip configure tests/use cached results/not rely
174 with codecs
.open("config.status", "w", "utf-8") as fh
:
180 from __future__ import unicode_literals
183 % {"python": config
["PYTHON3"]}
185 for k
, v
in sorted(six
.iteritems(sanitized_config
)):
186 fh
.write("%s = " % k
)
187 write_indented_repr(fh
, v
)
189 "__all__ = ['topobjdir', 'topsrcdir', 'defines', " "'substs', 'mozconfig']"
196 if __name__ == '__main__':
197 from mozbuild.config_status import config_status
198 args = dict([(name, globals()[name]) for name in __all__])
199 config_status(**args)
204 partial_config
= PartialConfigEnvironment(config
["TOPOBJDIR"])
205 partial_config
.write_vars(sanitized_config
)
207 # Write out a file so the build backend knows to re-run configure when
208 # relevant Python changes.
209 with io
.open("config_status_deps.in", "w", encoding
="utf-8", newline
="\n") as fh
:
212 config
["CONFIG_STATUS_DEPS"],
213 iter_modules_in_path(config
["TOPOBJDIR"], config
["TOPSRCDIR"]),
216 fh
.write("%s\n" % mozpath
.normpath(f
))
218 # Other things than us are going to run this file, so we need to give it
219 # executable permissions.
220 os
.chmod("config.status", 0o755)
222 from mozbuild
.config_status
import config_status
224 return config_status(args
=[], **sanitized_config
)
228 if __name__
== "__main__":
229 sys
.exit(main(sys
.argv
))