Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add os.sysarch() to get the architecture of the operating system #17036

Closed
sindresorhus opened this issue Nov 15, 2017 · 21 comments
Closed

Add os.sysarch() to get the architecture of the operating system #17036

sindresorhus opened this issue Nov 15, 2017 · 21 comments
Labels
feature request Issues that request new features to be added to Node.js. os Issues and PRs related to the os subsystem.

Comments

@sindresorhus
Copy link

sindresorhus commented Nov 15, 2017

Continued from nodejs/node-v0.x-archive#2862. // @Fishrock123 @isaacs @jasnell @feross

os.arch() returns the architecture of the Node.js process, not the operating system. This was surprising to me and many other Node.js users. I don't really see the usefulness of that, although there might be one. My main need is to know the architecture of the operating system so I can spawn the correct binary.

There is a clear need for it:


Update: Since this was declined, I made my own package for it: https://github.com/sindresorhus/system-architecture


@mscdex mscdex added feature request Issues that request new features to be added to Node.js. os Issues and PRs related to the os subsystem. labels Nov 15, 2017
@bnoordhuis
Copy link
Member

Raising the same point I raised in the archived issue: there is no right way to implement it on multi-arch systems. That's probably the majority of server and desktop Linux systems these days.

Three out of the four linked issues seem to be about 32 vs. 64 bits Windows. They're best off checking process.env.PROCESSOR_ARCHITECTURE and process.env.PROCESSOR_ARCHITEW6432, that's probably what a built-in function would do if we added one.

@Trott
Copy link
Member

Trott commented Dec 10, 2017

@sindresorhus Does @bnoordhuis's comment address your need? If not, do you have a proposal for what the correct behavior would be on a system with (quoting @bnoordhuis's example here) "a 32 bit kernel and a mostly 64 bit userland"?

Trying to nudge this in a direction where it's either actionable or else close-able....

Thanks!

@Fishrock123
Copy link
Member

Fishrock123 commented Dec 11, 2017

This seems like still a reasonable feature request to me.

Raising the same point I raised in the archived issue: there is no right way to implement it on multi-arch systems.

Huh? Are you sure can't make the API overcome that?

I don't think it needs to have the same API as os.arch()...

We could have it such like either of these:

This, where it is a checking function:

os.sysarch('x64') // true on 32&64bit compatible system
os.sysarch('x86') // also true on 32&64bit compatible system

Or this, where the first array value is the preferred one:

os.sysarch() === ['armv7'] // on an armv7 system
os.sysarch() === ['x64', 'x86'] // on say, a modern windows system

That seems like it would work to me, unless there for some reason isn't a way to get the architecture(s) of some systems correctly?

@bnoordhuis
Copy link
Member

Try it and see how far you get. I suspect this is one of those things that seem simple at the outset but aren't.

Just one example: what should it print for a 64 bits kernel with a 32 bits emulation layer but without a 32 bits userland? How would you even go about figuring out if either condition is true?

@tniessen
Copy link
Member

tniessen commented Dec 11, 2017

@Fishrock123 I gave this a try a couple of weeks ago and it is easy to implement on certain platforms (e.g. Windows), but I failed to find a simple way on Linux / Unix-like platforms. I didn't expect it to be difficult either, e.g. Android has a very nice API for this (SUPPORTED_ABIS). You can start by looking at what uname and dpkg do to determine the correct platforms / architectures.

@Fishrock123
Copy link
Member

Just one example: what should it print for a 64 bits kernel with a 32 bits emulation layer but without a 32 bits userland?

Heh. My knowledge doesn't extend that far but is it actually impossible to tell from that if it can/can't run a 64 or 32 bit binary? If we can't tell which order it should be in for preference we could just hardcode it to return in some order, so long as that ordering would normally work.

@bnoordhuis
Copy link
Member

bnoordhuis commented Dec 11, 2017

Well, that's what I mean with it gets complicated fast. The absence of a 32 bits userland doesn't mean 32 bits binaries won't work. Anything that is fully statically linked will run just fine; everything else won't.

@tniessen Here is how to do it on Linux:

#include <stdio.h>
#include <sys/personality.h>
#include <sys/syscall.h>
#include <unistd.h>

int main(void) {
  int ok = 0;
  if (PER_LINUX == syscall(__NR_personality, PER_LINUX32))
    if (PER_LINUX32 == syscall(__NR_personality, PER_LINUX))
      ok = 1;
  if (ok)
    puts("32 bits syscalls supported");
  return !ok;
}

Unfortunately, there is no way to change the personality in a thread-safe manner - it's a per-thread property, not per-process.

@tniessen
Copy link
Member

@bnoordhuis As far as I can tell, that should be sufficient to check whether a Linux system can execute 32 bit code. I don't think we can derive any other information about the "OS architecture" / supported ABIs from this.

@gireeshpunathil
Copy link
Member

from the requirement:

My main need is to know the architecture of the operating system so I can spawn the correct binary.

It appears to me that knowing the prominent or original capability of the host OS is sufficient to select a binary, not necessarily all the supported / emulated combinations / capabilities of the host.

@sindresorhus - can you clarify this? Is the feature supposed to:

  • Retrieve an array of tokens, wherein each token represents a supported architecture
    or
  • Retrieve the most appropriate token that represents the native architecture of the os?

If second is the case, the below snippet looks to be enough on UNIX platforms:

#include <sys/utsname.h>
#include <stdio.h>

int main() {
  struct utsname u;
  uname(&u);
  fprintf(stderr, "%s\n", u.machine);
}

@tniessen
Copy link
Member

@gireeshpunathil, isn't utsname.machine a hardware property? I always assumed it does not necessarly represent the kernel architecture, e.g. when installing a "32 bit os" on a 64 bit machine.

@gireeshpunathil
Copy link
Member

@tniessen - yes, it is the h/w property. But when we are talking about selecting the right binary / image, aren't we aiming to match the h/w architecture, as opposed to that of the driving kernel?

For example, gcc's codegen flag spec says:
-m32 -m64 Generate code for a 32-bit or 64-bit environment. The 32-bit environment sets int, long and pointer to 32 bits and generates code that runs on any i386 system. The 64-bit environment sets int to 32 bits and long and pointer to 64 bits and generates code for AMD’s x86-64 architecture. For darwin only the -m64 option turns off the -fno-pic and -mdynamic-no-pic options.

So here the environment actually means the h/w, not the OS right? Or Am I missing something?

@gireeshpunathil
Copy link
Member

We are using the same technique to build and run node on a given UNIX host:

UNAME_M=$(shell uname -m)
ifeq ($(findstring x86_64,$(UNAME_M)),x86_64)
DESTCPU ?= x64
else
ifeq ($(findstring ppc64,$(UNAME_M)),ppc64)
DESTCPU ?= ppc64
else

@bnoordhuis
Copy link
Member

That's just an educated guess. On Linux, uname -m reflects the active personality. With setarch i686 make, it detects x86.

If the platform ABI is important too, then I don't know of a reliable way to detect that.

@gibfahn
Copy link
Member

gibfahn commented Dec 28, 2017

Looking at the linked issues, it seems that the most common use-case is to detect people running 32-bit node on a 64-bit machine, e.g. to suggest that they download the 64-bit node and use that instead.

From one of the linked issues I came across @feross's arch module, which gives you a best guess at whether the machine supports 64-bit or not.

Is there a use-case for which that module is insufficient?

@gibfahn
Copy link
Member

gibfahn commented Dec 28, 2017

My main need is to know the architecture of the operating system so I can spawn the correct binary.

What is the issue with using os.arch() here? If os.arch() is x64, then you're good to use 64-bit binaries. If it's ia32, then you should be find with 32-bit binaries. I understand wanting to use 64-bit where possible, but using 32-bit binaries if os.arch() returns ia32 should be fine (just not ideal).

@tniessen
Copy link
Member

@gibfahn I can think of two hypothetical use cases:

  • Spawning a process which might use a lot of memory, using a 32 bit binary on a 64 bit machine would unnecessarily limit it to 4GB.
  • Windows installers should usually target the "os architecture" (because WoW64 really is not that pretty after all).

@gibfahn
Copy link
Member

gibfahn commented Dec 28, 2017

I can think of two hypothetical use cases:

Fair enough, but then we're back to #17036 (comment), and feross/arch seems sufficient (especially as those seem like niche use cases).

@tniessen
Copy link
Member

@gibfahn Sure, those were just the two for which os.arch() itself might not be sufficient. You are right about using arch!

@Ginden
Copy link

Ginden commented Jan 9, 2018

Spawning a process which might use a lot of memory, using a 32 bit binary on a 64 bit machine would unnecessarily limit it to 4GB.

This limit applies almost exclusively to consumer 32-bit Windows and 32-bit ARMs before V7A. Most of Linux distributions and 32-bit Windows Server support bigger memory (but it's still up to 4GB per process). Physical Address Extension.

@gireeshpunathil
Copy link
Member

where does this stand now? do we have a consensus on what are valid use cases and what would work in which cases?

@bnoordhuis
Copy link
Member

I think there are too many caveats to get this right in general, and for the simple case, https://github.com/feross/arch works fine and doesn't need to be in core. I'll close this out.

theofficialgman added a commit to theofficialgman/desktop that referenced this issue Jul 7, 2023
os.arch should not be used and its output does not correlate with the expected output. the actual output of os.arch is identical to process.arch while you would expect it to be the OS architecture and not the architecture that nodejs is compiled for. This has no change on functionality.
nodejs/node-v0.x-archive#2862
nodejs/node#17036
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request Issues that request new features to be added to Node.js. os Issues and PRs related to the os subsystem.
Projects
None yet
Development

No branches or pull requests

9 participants