mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
249 lines
10 KiB
JavaScript
249 lines
10 KiB
JavaScript
var _ = require('underscore');
|
|
var files = require('./files.js');
|
|
var os = require('os');
|
|
|
|
/* Meteor's current architecture scheme defines the following virtual
|
|
* machine types, which are defined by specifying what is promised by
|
|
* the host enviroment:
|
|
*
|
|
* browser.w3c
|
|
* A web browser compliant with modern standards. This is
|
|
* intentionally a broad definition. In the coming years, as web
|
|
* standards evolve, we will likely tighten it up.
|
|
*
|
|
* browser.ie[678]
|
|
* Old versions of Internet Explorer (not sure yet exactly which
|
|
* versions to distinguish -- maybe 6 and 8?)
|
|
*
|
|
* os.linux.x86_32
|
|
* os.linux.x86_64
|
|
* Linux on Intel x86 architecture. x86_64 means a system that can
|
|
* run 64-bit images, furnished with 64-bit builds of shared
|
|
* libraries (there is no guarantee that 32-bit builds of shared
|
|
* libraries will be available). x86_32 means a system that can run
|
|
* 32-bit images, furnished with 32-bit builds of shared libraries.
|
|
* Additionally, if a package contains shared libraries (for use by
|
|
* other packages), then if the package is built for x86_64, it
|
|
* should contain a 64-bit version of the library, and likewise for
|
|
* 32-bit.
|
|
*
|
|
* Operationally speaking, if you worked at it, under this
|
|
* definition it would be possible to build a Linux system that can
|
|
* run both x86_64 and x86_32 images (eg, by using a 64-bit kernel
|
|
* and making sure that both versions of all relevant libraries were
|
|
* installed). But we require such a host to decide whether it is
|
|
* x86_64 or x86_32, and stick with it. You can't load a combination
|
|
* of packages from each and expect them to work together, because
|
|
* if they contain shared libraries they all need to have the same
|
|
* architecture.
|
|
*
|
|
* Basically the punchline is: if you installed the 32-bit version
|
|
* of Ubuntu, you've got a os.linux.x86_32 system and you will
|
|
* use exclusively os.linux.x86_32 packages, and likewise
|
|
* 64-bit. They are two parallel universes and which one you're in
|
|
* is determined by which version of Red Hat or Ubuntu you
|
|
* installed.
|
|
*
|
|
* os.osx.x86_64
|
|
* OS X (technically speaking, Darwin) on Intel x86 architecture,
|
|
* with a kernel capable of loading 64-bit images, and 64-bit builds
|
|
* of shared libraries available. If a os.osx.x86_64 package
|
|
* contains a shared library, it is only required to provide a
|
|
* 64-bit version of the library (it is not required to provide a
|
|
* fat binary with both 32-bit and 64-bit builds).
|
|
*
|
|
* Note that in modern Darwin, both the 32 and 64 bit versions of
|
|
* the kernel can load 64-bit images, and the Apple-supplied shared
|
|
* libraries are fat binaries that include both 32-bit and 64-bit
|
|
* builds in a single file. So it is technically fine (but
|
|
* discouraged) for a os.osx.x86_64 to include a 32-bit
|
|
* executable, if it only uses the system's shared libraries, but
|
|
* you'll run into problems if shared libraries from other packages
|
|
* are used.
|
|
*
|
|
* There is no os.osx.x86_32. Our experience is that such
|
|
* hardware is virtually extinct. Meteor has never supported it and
|
|
* nobody has asked for it.
|
|
*
|
|
* os.windows.x86_32
|
|
* This is 32 and 64 bit Windows. It seems like there is not much of
|
|
* a benefit to using 64 bit Node on Windows, and 32 bit works properly
|
|
* even on 64 bit systems.
|
|
*
|
|
* To be (more but far from completely) precise, the ABI for os.*
|
|
* architectures includes a CPU type, a mode in which the code will be
|
|
* run (eg, 64 bit), an executable file format (eg, ELF), a promise to
|
|
* make any shared libraries available in a particular architecture,
|
|
* and promise to set up the shared library search path
|
|
* "appropriately". In the future it will also include some guarantees
|
|
* about the directory layout in the environment, eg, location of a
|
|
* directory where temporary files may be freely written. It does not
|
|
* include any syscalls (beyond those used by code that customarily is
|
|
* statically linked into every executable built on a platform, eg,
|
|
* exit(2)). It does not guarantee the presence of any particular
|
|
* shared libraries or programs (including any particular shell or
|
|
* traditional tools like 'grep' or 'find').
|
|
*
|
|
* To model the shared libraries that are required on a system (and
|
|
* the particular versions that are required), and to model
|
|
* dependencies on command-line programs like 'bash' and 'grep', the
|
|
* idea is to have a package named something like 'posix-base' that
|
|
* rolls up a reasonable base environment (including such modern
|
|
* niceties as libopenssl) and is supplied by the container. This
|
|
* allows it to be versioned, unlike architectures, which we hope to
|
|
* avoid versioning.
|
|
*
|
|
* Q: What does "x86" mean?
|
|
* A: It refers to the traditional Intel architecture, which
|
|
* originally surfaced in CPUs such as the 8086 and the 80386. Those
|
|
* of us who are older should remember that the last time that Intel
|
|
* used this branding was the 80486, introduced in 1989, and that
|
|
* today, parts that use this architecture bear names like "Core",
|
|
* "Atom", and "Phenom", with no "86" it sight. We use it in the
|
|
* architecture name anyway because we don't want to depart too far
|
|
* from Linux's architecture names.
|
|
*
|
|
* Q: Why do we call it "x86_32" instead of the customary "i386" or
|
|
* "i686"?
|
|
* A: We wanted to have one name for 32-bit and one name for 64-bit,
|
|
* rather than several names for each that are virtual synonyms for
|
|
* each (eg, x86_64 vs amd64 vs ia64, i386 vs i686 vs x86). For the
|
|
* moment anyway, we're willing to adopt a "one size fits all"
|
|
* attitude to get there (no ability to have separate builds for 80386
|
|
* CPUs that don't support Pentium Pro extensions, for example --
|
|
* you'll have to do runtime detection if you need that). And as long
|
|
* as we have to pick a name, we wanted to pick one that was super
|
|
* clear (it is not obvious to many people that "i686" means "32-bit
|
|
* Intel", because why should it be?) and didn't imply too close of an
|
|
* equivalence to the precise meanings that other platforms may assign
|
|
* to some of these strings.
|
|
*/
|
|
|
|
|
|
// Returns the fully qualified arch of this host -- something like
|
|
// "os.linux.x86_32" or "os.osx.x86_64". Must be called inside
|
|
// a fiber. Throws an error if it's not a supported architecture.
|
|
//
|
|
// If you change this, also change scripts/admin/launch-meteor
|
|
var _host = null; // memoize
|
|
var host = function () {
|
|
if (! _host) {
|
|
var run = function (/* arguments */) {
|
|
var result = files.run.apply(null, arguments);
|
|
if (! result)
|
|
throw new Error("can't get arch with " +
|
|
_.toArray(arguments).join(" ") + "?");
|
|
return result.replace(/\s*$/, ''); // trailing whitespace
|
|
};
|
|
|
|
var platform = os.platform();
|
|
|
|
if (platform === "darwin") {
|
|
// Can't just test uname -m = x86_64, because Snow Leopard can
|
|
// return other values.
|
|
if (run('uname', '-p') !== "i386" ||
|
|
run('sysctl', '-n', 'hw.cpu64bit_capable') !== "1")
|
|
throw new Error("Only 64-bit Intel processors are supported on OS X");
|
|
_host = "os.osx.x86_64";
|
|
}
|
|
|
|
else if (platform === "linux") {
|
|
var machine = run('uname', '-m');
|
|
if (_.contains(["i386", "i686", "x86"], machine))
|
|
_host = "os.linux.x86_32";
|
|
else if (_.contains(["x86_64", "amd64", "ia64"], machine))
|
|
_host = "os.linux.x86_64";
|
|
else
|
|
throw new Error("Unsupported architecture: " + machine);
|
|
}
|
|
|
|
else if (platform === "win32") {
|
|
// We also use 32 bit builds on 64 bit Windows architectures.
|
|
_host = "os.windows.x86_32";
|
|
}
|
|
|
|
else
|
|
throw new Error("Unsupported operating system: " + platform);
|
|
}
|
|
|
|
return _host;
|
|
};
|
|
|
|
// True if `host` (an architecture name such as 'os.linux.x86_64') can run
|
|
// programs of architecture `program` (which might be something like 'os',
|
|
// 'os.linux', or 'os.linux.x86_64').
|
|
//
|
|
// `host` and `program` are just mnemonics -- `host` does not
|
|
// necessariy have to be a fully qualified architecture name. This
|
|
// function just checks to see if `program` describes a set of
|
|
// enviroments that is a (non-strict) superset of `host`.
|
|
var matches = function (host, program) {
|
|
return host.substr(0, program.length) === program &&
|
|
(host.length === program.length ||
|
|
host.substr(program.length, 1) === ".");
|
|
};
|
|
|
|
// Like `supports`, but instead taken an array of possible
|
|
// architectures as its second argument. Returns the most specific
|
|
// match, or null if none match. Throws an error if `programs`
|
|
// contains exact duplicates.
|
|
var mostSpecificMatch = function (host, programs) {
|
|
var seen = {};
|
|
var best = null;
|
|
|
|
_.each(programs, function (p) {
|
|
if (seen[p])
|
|
throw new Error("Duplicate architecture: " + p);
|
|
seen[p] = true;
|
|
if (archinfo.matches(host, p) &&
|
|
(! best || p.length > best.length))
|
|
best = p;
|
|
});
|
|
|
|
return best;
|
|
};
|
|
|
|
// `programs` is a set of architectures (as an array of string, which
|
|
// may contain duplicates). Determine if there exists any architecture
|
|
// that is compatible with all of the architectures in the set. If so,
|
|
// returns the least specific such architecture. Otherwise (the
|
|
// architectures are disjoin) raise an exception.
|
|
//
|
|
// For example, for 'os' and 'os.osx', return 'os.osx'. For 'os' and
|
|
// 'os.linux.x86_64', return 'os.linux.x86_64'. For 'os' and 'browser', throw an
|
|
// exception.
|
|
var leastSpecificDescription = function (programs) {
|
|
if (programs.length === 0)
|
|
return '';
|
|
|
|
// Find the longest string
|
|
var longest = _.max(programs, function (p) { return p.length; });
|
|
|
|
// If everything else in the list is compatible with the longest,
|
|
// then it must be the most specific, and if everything is
|
|
// compatible with the most specific then it must be the least
|
|
// specific compatible description.
|
|
_.each(programs, function (p) {
|
|
if (! archinfo.matches(longest, p))
|
|
throw new Error("Incompatible architectures: '" + p + "' and '" +
|
|
longest + "'");
|
|
});
|
|
|
|
return longest;
|
|
};
|
|
|
|
var withoutSpecificOs = function (arch) {
|
|
if (arch.substr(0, 3) === 'os.')
|
|
return 'os';
|
|
return arch;
|
|
};
|
|
|
|
var archinfo = exports;
|
|
_.extend(archinfo, {
|
|
host: host,
|
|
matches: matches,
|
|
mostSpecificMatch: mostSpecificMatch,
|
|
leastSpecificDescription: leastSpecificDescription,
|
|
withoutSpecificOs: withoutSpecificOs
|
|
});
|