Skip to content

Conversation

heinthanth
Copy link

The patch is quite simple.

choosenim use proxyexe that is statically compiled and statically read and is embedded in choosenim like this:

static: compileProxyexe()

const
  proxyExe = staticRead("proxyexe".addFileExt(ExeExt))

Instead of statically compiled proxyexe, I patched the compileProxyexe proc to compile proxyexe on user machine with embedded source code and previously compiled Nim like this:

const proxyExeSources = {
  "src" / "choosenimpkg" / "proxyexe.nim": staticRead("./proxyexe.nim"),
  "src" / "choosenimpkg" / "proxyexe.nims": staticRead("./proxyexe.nims"),
  "src" / "choosenimpkg" / "common.nim": staticRead("./common.nim"),
  "src" / "choosenimpkg" / "cliparams.nim": staticRead("./cliparams.nim"),
  "choosenim.nimble": staticRead("../../choosenim.nimble")
}.toTable()

I mean I embedded source codes required by proxyexe on choosenim binary. Then, I compiled them with previously compiled arm64 nim and nimble binaries ( choosenim compile nim first, then write proxy ).

Yeah, this is the main trick. And also on M1 macs with rosetta, I appended arch -arm64 flags on most commands to run as arm process like this:

if defined(macosx) and isRosetta():
  command = "arch -arm64 " & command

You can mark this PR as draft. On my mac, it works fine. How about others?

@elcritch
Copy link
Contributor

elcritch commented Jul 8, 2022

I cloned this PR and rebuilt choosenim. That seems fine so far.

Running choosenim devel resulted in this:

$ choosenim devel         
Downloading Nim latest-devel from GitHub
[##################################################] 100.0% 0kb/s
 Extracting macosx_x64.tar.xz
 Extracting macosx_x64.tar
    Setting up git repository
   Building Nim #devel
  Compiler: Already built
  Building: ProxyExe
 Exception: switcher.nim(46, 12) `exitCode == 0` ("arch: posix_spawnp: /Users/jaremycreechley/.choosenim/toolchains/nim-#devel/bin/nimble: Bad CPU type in executable\n", "arch -arm64 /Users/jaremycreechley/.choosenim/toolchains/nim-#devel/bin/nimble --nim:\'/Users/jaremycreechley/.choosenim/toolchains/nim-#devel/bin/nim\' c -d:release /var/folders/dl/98d12czj5_b9lyfvzykftzt80000gn/T/proxyexe/src/choosenimpkg/proxyexe.nim")
   Cleaning failed install of #devel
       Tip: 9 messages have been suppressed, use --verbose to show them.
     Error: Installation failed

It seems to work with choosenim 1.4.4:

$ choosenim 1.4.4 
Downloading Nim 1.4.4 from nim-lang.org
[##################################################] 100.0% 0kb/s
 Extracting nim-1.4.4.tar.xz
 Extracting nim-1.4.4.tar
   Building Nim 1.4.4
   Building koch
   Building Nim
   Building tools (nimble, nimgrep, nimpretty, nimsuggest, testament)
  Building: ProxyExe
  Installed component 'nim'
    Prompt: Symlink for 'nimble' detected in '/Users/jaremycreechley/.nimble/bin'. Can I remove it? [y/N]
    Answer: y
    Removed symlink pointing to ../pkgs/nimble-#8f7af86/nimble
  Installed component 'nimble'
  Installed component 'nimgrep'
  Installed component 'nimpretty'
  Installed component 'nimsuggest'
  Installed component 'testament'
  Installed component 'nim-gdb'
   Switched to Nim 1.4.4

# jaremycreechley @ Jaremys-MacBook-Air in ~/projs/nims/third-party/choosenim on git:master o [22:18:28] 
$ nim -v
Nim Compiler Version 1.4.4 [MacOSX: arm64]
Compiled at 2022-07-08
Copyright (c) 2006-2020 by Andreas Rumpf

active boot switches: -d:release

However running choosenim 1.6.4 (I'm on 1.6.6):

$ choosenim 1.6.4
Downloading Nim 1.6.4 from nim-lang.org
[##################################################] 100.0% 0kb/s
 Extracting nim-1.6.4.tar.xz
 Extracting nim-1.6.4.tar
   Building Nim 1.6.4
   Building koch
   Building Nim
   Building tools (nimble, nimgrep, nimpretty, nimsuggest, testament)
  Building: ProxyExe
  Installed component 'nim'
  Installed component 'nimble'
  Installed component 'nimgrep'
  Installed component 'nimpretty'
  Installed component 'nimsuggest'
  Installed component 'testament'
  Installed component 'nim-gdb'
   Switched to Nim 1.6.4

# jaremycreechley @ Jaremys-MacBook-Air in ~/projs/nims/third-party/choosenim on git:master o [22:23:51] 
$ nim -v 
[1]    92907 killed     nim -v

Here's trying to re-install 1.6.6:

$ choosenim 1.6.6
  Building: ProxyExe
 Exception: switcher.nim(46, 12) `exitCode == 0` ("arch: posix_spawnp: /Users/jaremycreechley/.choosenim/toolchains/nim-1.6.6/bin/nimble: Bad CPU type in executable\n", "arch -arm64 /Users/jaremycreechley/.choosenim/toolchains/nim-1.6.6/bin/nimble --nim:\'/Users/jaremycreechley/.choosenim/toolchains/nim-1.6.6/bin/nim\' c -d:release /var/folders/dl/98d12czj5_b9lyfvzykftzt80000gn/T/proxyexe/src/choosenimpkg/proxyexe.nim")
     Error: Installation failed

Lastly:

$ file $(which nim)
/Users/jaremycreechley/.nimble/bin/nim: Mach-O 64-bit executable arm64

@elcritch
Copy link
Contributor

elcritch commented Jul 8, 2022

P.S. I'm on a MacOS Monterey 12.0.1 (21A559) on a M1 MacBook Air.

@heinthanth
Copy link
Author

heinthanth commented Jul 8, 2022

I see ... let me try those versions.

Edit: I assumed choosenim to download nim sources. Instead, choosenim download specific x64 nim for those versions. I gonna check that out.

Here're differences:

nim devel: macosx_x64.tar.xz

Downloading Nim latest-devel from GitHub
[##################################################] 100.0% 0kb/s
 Extracting macosx_x64.tar.xz

nim 1.4.4: nim-1.4.4.tar.xz

Downloading Nim 1.4.4 from nim-lang.org
[##################################################] 100.0% 0kb/s
 Extracting nim-1.4.4.tar.xz

Like that.

For 1.6.6, I think you already have x64 Nim binaries.

@elcritch
Copy link
Contributor

elcritch commented Jul 8, 2022

It seems mixing up the sources, or partial builds breaks things. I did a fresh install on choosenim, then built this PR. That route was able to download and build Nim 1.6.4 which runs fine.

@elcritch
Copy link
Contributor

elcritch commented Jul 8, 2022

Though once I have an arm64 build of 1.6.4 when I try remove and rebuild 1.6.6 I still get a bad compiler build:

# jaremycreechley @ Jaremys-MacBook-Air in ~/projs/nims/third-party/choosenim on git:master o [23:05:15] 
$ ./bin/choosenim remove 1.6.6                         
      Info: Removed version 1.6.6

# jaremycreechley @ Jaremys-MacBook-Air in ~/projs/nims/third-party/choosenim on git:master o [23:05:42] 
$ ./bin/choosenim 1.6.6       
Downloading Nim 1.6.6 from nim-lang.org
[##################################################] 100.0% 0kb/s
 Extracting nim-1.6.6.tar.xz
 Extracting nim-1.6.6.tar
   Building Nim 1.6.6
   Building koch
   Building Nim
   Building tools (nimble, nimgrep, nimpretty, nimsuggest, testament)
  Building: ProxyExe
  Installed component 'nim'
  Installed component 'nimble'
  Installed component 'nimgrep'
  Installed component 'nimpretty'
  Installed component 'nimsuggest'
  Installed component 'testament'
  Installed component 'nim-gdb'
   Switched to Nim 1.6.6

# jaremycreechley @ Jaremys-MacBook-Air in ~/projs/nims/third-party/choosenim on git:master o [23:07:32] 
$ nim -v 
[1]    7211 killed     nim -v

Binary seems like it's an arm64:

$ file $(which nim)      
/Users/jaremycreechley/.nimble/bin/nim: Mach-O 64-bit executable arm64

@heinthanth
Copy link
Author

heinthanth commented Jul 8, 2022

I'm figuring out about why process is killed and I found something like this: "code signing rejecting invalid page at address"
So, now, I'm rebuilding ProxyExe when a version is selected. That killed problem should be fine with this commit ( coming soon )

@elcritch
Copy link
Contributor

elcritch commented Jul 8, 2022

Great, and yah that follows what I'm seeing with ProxeExe. I re-installed choosenim and then my Nim 1.6.6 arm64 build worked. The ProxyExe seemed to be breaking between choosenim installs.

@heinthanth
Copy link
Author

heinthanth commented Jul 8, 2022

@elcritch You can try again now. I think it should fix killed problem. For the bug that choosenim downloading x64.tar.xz, we need to figure out download.nim.

As far as I tested, I can switch between 1.4.4, 1.6.4, 1.6.6 fine!

@heinthanth
Copy link
Author

But for the case that choosenim downloading macos_x64.tar.xz, I think I need @dom96 's help 😁.

@elcritch
Copy link
Contributor

elcritch commented Jul 8, 2022

I'm re-testing your updates. I'll let you know how it goes.

@elcritch
Copy link
Contributor

elcritch commented Jul 8, 2022

Ok did some testing. It works when using a default choosenim and then use this PR to install a new Nim version.

However when I do a choosenim stable --firstInstall after deleting my ~/.nimble and ~/.choosenim folders. It builds the compiler fine but then gets to this error:

 Executing: arch -arm64 /Users/jaremycreechley/.choosenim/toolchains/nim-1.6.6/bin/nimble --nim:'/Users/jaremycreechley/.choosenim/toolchains/nim-1.6.6/bin/nim' c -d:release /var/folders/dl/98d12czj5_b9lyfvzykftzt80000gn/T/proxyexe/src/choosenimpkg/proxyexe.nim
 Exception: switcher.nim(46, 12) `exitCode == 0` ("  Verifying dependencies for choosenim@0.8.4\n    Prompt: No local packages.json found, download it from internet? [y/N]\nio.nim(156)              raiseEOF\nError: unhandled exception: EOF reached [EOFError]\n    Answer: \n", "arch -arm64 /Users/jaremycreechley/.choosenim/toolchains/nim-1.6.6/bin/nimble --nim:\'/Users/jaremycreechley/.choosenim/toolchains/nim-1.6.6/bin/nim\' c -d:release /var/folders/dl/98d12czj5_b9lyfvzykftzt80000gn/T/proxyexe/src/choosenimpkg/proxyexe.nim")
   Cleaning failed install of 1.6.6
     Debug: Reporting to analytics...
     Debug: Reporting to analytics...
     Debug: Reporting to analytics...
     Error: Installation failed

@heinthanth
Copy link
Author

Yeah ... I forgot to add -y in nimble while compiling proxies. For now, I've tested and OK!

Screen Shot 2022-07-08 at 4 43 18 PM

@elcritch
Copy link
Contributor

elcritch commented Jul 8, 2022

Nice! I added the -y locally and it works for me as well. But is the Symlink for 'nimble' detected... expected? It seems for --firstInstall it should override it?

@elcritch
Copy link
Contributor

elcritch commented Jul 8, 2022

Maybe you could add if symlinkExists(proxyPath) and not params.firstInstall: in switcher.nim:160?

@elcritch
Copy link
Contributor

elcritch commented Jul 8, 2022

Adding the if symlinkExists(proxyPath) and not params.firstInstall fixes that too. Excellent!

Edit: also just tested this on a linux machine of mine. Works fine.

@elcritch
Copy link
Contributor

elcritch commented Jul 8, 2022

Oh, the compiler runs much faster when it's not using Rosetta! ❤️

@heinthanth
Copy link
Author

heinthanth commented Jul 8, 2022

Yes, we can override nimble in firstInstall. Because it's from proxyexe.nimble deps! Cool, thanks for info!

Screen Shot 2022-07-08 at 5 13 21 PM

Here:

Screen Shot 2022-07-08 at 5 15 24 PM

@heinthanth
Copy link
Author

heinthanth commented Jul 8, 2022

Huge thanks @elcritch. We can build choosenim universal binary after this by tweaking build.sh since we separated proxyExe from choosenim 🚀

@elcritch
Copy link
Contributor

elcritch commented Jul 8, 2022

Glad to help!

@heinthanth
Copy link
Author

@dom96 We made progress so far 😁 What do you think?

Copy link
Owner

@dom96 dom96 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome collab between both of you here. Thank you!

I haven't read all the discussion in detail so please forgive me if I missed something, but here are my questions from just looking at the code:

  • The proxyexe is now compiled at choosenim runtime. Can we do it at compile-time as it was done before? I'm concerned that performing this at runtime will be too unreliable.
  • In general I'm wondering: do we need proxyexe and choosenim to be compiled as arm64? Can't we just keep the changes in utils.nim and have choosenim make an arm64 Nim build with just these changes?

@heinthanth
Copy link
Author

heinthanth commented Jul 8, 2022

The proxyexe is now compiled at choosenim runtime. Can we do it at compile-time as it was done before? I'm concerned that performing this at runtime will be too unreliable.

We can pre-compile proxies as usual. But we need to build choosenim binaries ( amd64 and arm64 ) because proxies must be arm64 on M1 macs and amd64 on amd64. Or we can build universal proxies I think.

In general I'm wondering: do we need proxyexe and choosenim to be compiled as arm64? Can't we just keep the changes in utils.nim and have choosenim make an arm64 Nim build with just these changes?

Here's the case:

  1. Let compiler.nim be nim compiler itself ( I think nim internal work something like this ). This invokes C compiler and compiles test.c.
import os, osproc, strutils

let (output, exitCode) = execCmdEx("cc -o $# test.c" % "test".addFileExt(ExeExt))
assert exitCode == 0, output

And it's compiled in arm64.

[ heinthant@macbookpro ] codes/heinthant/nim-demo $ file compiler           
compiler: Mach-O 64-bit executable arm64
  1. Let proxies.nim be proxies from choosenim. This starts compiler process.
import os, osproc

const nimBin = "compiler".addFileExt(ExeExt)

let nimProcess = startProcess(nimBin)
let exitCode = nimProcess.waitForExit()
nimProcess.close()

assert exitCode == 0

This is compiled in x86_64.

[ heinthant@macbookpro ] codes/heinthant/nim-demo $ file proxies
proxies: Mach-O 64-bit executable x86_64

The strange case is:

  1. When I direct-invoke compiler, the output from test.c is arm64.
[ heinthant@macbookpro ] codes/heinthant/nim-demo $ ./compiler
[ heinthant@macbookpro ] codes/heinthant/nim-demo $ file test
test: Mach-O 64-bit executable arm64
  1. But when I invoke compiler via proxies, the output from test.c is amd64 ( although compiler is arm64 but cc is universal )
[ heinthant@macbookpro ] codes/heinthant/nim-demo $ ./proxies
[ heinthant@macbookpro ] codes/heinthant/nim-demo $ file test
test: Mach-O 64-bit executable x86_64

So, to conclude, I believe, although nim binaries are arm64, when invoked via amd64 proxies, the compiler output will be amd64 due to universal C compilers from macOS.

We DON'T NEED choosenim itself to be universal or arm64. But we need proxies to be arm64.

@heinthanth
Copy link
Author

heinthanth commented Jul 8, 2022

@dom96, Ahh ... I get it ... we can build universal proxies on mac. So, we can accomplish with minimal changes

@heinthanth
Copy link
Author

heinthanth commented Jul 8, 2022

@elcritch @dom96 We combined ideas together 🍻

But there's an issue left: Choosenim is downloading x64 tar in devel channel. Other than that, choosenim can build arm64 nim binaries.

The proxyexe is now compiled at choosenim runtime. Can we do it at compile-time as it was done before? I'm concerned that performing this at runtime will be too unreliable.

Solved! ( Proxies are compiled and embed in choosenim )

In general I'm wondering: do we need proxyexe and choosenim to be compiled as arm64? Can't we just keep the changes in utils.nim and have choosenim make an arm64 Nim build with just these changes?

Yeah, like above explanation, proxies need to be arm64 on M1 macs, so I build universal proxies. Solved!

I think we can merge this now after some testing.

Copy link
Owner

@dom96 dom96 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Beautiful.

But there's an issue left: Choosenim is downloading x64 tar in devel channel. Other than that, choosenim can build arm64 nim binaries.

You should be able to find the code responsible for this by searching for this constant ident: https://github.com/dom96/choosenim/blob/master/src/choosenimpkg/download.nim#L14

Co-authored-by: Dominik Picheta <dominikpicheta@googlemail.com>
@heinthanth
Copy link
Author

Cool, resolved suggestions from reviews.

@heinthanth
Copy link
Author

Cool, I also fixed choosenim downloading x64 prebuilt binaries on devel channel.

if not isRosetta() and hostCPU == "amd64":

that did the trick. On my machine, choosenim works fine! How about yours?

Copy link
Owner

@dom96 dom96 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one thing, other than that looks good. Thank you so much for working on this!

@heinthanth
Copy link
Author

heinthanth commented Jul 10, 2022

@dom96

macOS without Rosetta

I added several checks ( isAppleSilicon, isMacOSBelowBigSurCompileTime, isMacOSBelowBigSur ).

isMacOSBelowBigSurCompileTime check during compile-time ( build machine )

if build machine is below macOS Big Sur, arm64 proxies won't be embedded and that choosenim build cannot be used on Apple Silicon macs. Otherwise, two proxies ( amd64 and arm64 ) will be embedded.

isMacOSBelowBigSur check during run-time ( user machine )

if user machine is below Big Sur, amd64 proxies will be used.
if user machine is MacOS Big Sur and above, I checked isAppleSilicon.
if AppleSilicon, choosenim will install arm64 proxies, Otherwise, amd64 proxies will be installed.

So, I think this will solve upcoming problems on MacOS like Catalina, Mojave, etc. ( macOS on Intel but without rosetta )
For older macOS, above trick will works too.

For Linux and Windows, normal host-specific proxyExe is embedded too.


choosenim itself cannot run on older macOS

But for this case, I think we need to tweak build.sh providing min-macos version like @elcritch said.

@esafak
Copy link

esafak commented Oct 2, 2022

Are we waiting for something to merge this?

@shish
Copy link

shish commented Dec 31, 2022

Also eagerly awaiting any updates here, as I keep having issues with different nim installs (brew, nix, and choosenim) and this issue seems like the closest to being fixed :)

@ujwal-setlur
Copy link

Any update on this PR? Looks like it is ready to go?

@lantos1618
Copy link

still waiting on approval?

@heinthanth
Copy link
Author

heinthanth commented Mar 31, 2023 via email

@lewisl
Copy link

lewisl commented Aug 30, 2024

This all looks good, but really it doesn't seem to work when using choosenim to build on an M1 MacBook. Is the --firstinstall option required?

@heinthanth
Copy link
Author

@lewisl Hi, use the fork from https://github.com/nim-lang/choosenim

@lewisl
Copy link

lewisl commented Aug 31, 2024 via email

@heinthanth
Copy link
Author

I'll close this PR as we should use https://github.com/nim-lang/choosenim fork instead of this one.

@heinthanth heinthanth closed this Aug 31, 2024
@lewisl
Copy link

lewisl commented Aug 31, 2024 via email

@heinthanth
Copy link
Author

@lewisl, I don't think so. The fork is under official Nim organization. I think that will be the one actively maintained.

@lewisl
Copy link

lewisl commented Aug 31, 2024 via email

@lewisl
Copy link

lewisl commented Aug 31, 2024 via email

@lewisl
Copy link

lewisl commented Aug 31, 2024 via email

@heinthanth
Copy link
Author

@lewisl this PR is merged to the fork just 2 days ago and the script is not updated yet.

But I saw Ringabout created a test CI/CD for arm64 build. You can try this release https://github.com/nim-lang/choosenim/releases/tag/master. There's arm64 binary and let us know.

@lewisl
Copy link

lewisl commented Aug 31, 2024 via email

@lewisl
Copy link

lewisl commented Aug 31, 2024 via email

@heinthanth
Copy link
Author

@lewisl yes, I agree. Script helps alot easier. But I think those are still in progress. I saw Apple Silicon Github action was setup in the fork. So, I hope these issues will be solved in near future.

Since I got Apple Silicon machines, I was building Nim from source.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants