asdf-vm / asdf-erlang

Erlang plugin for asdf version manager
https://github.com/asdf-vm/asdf
MIT License
482 stars 119 forks source link

Cannot build with ODBC support on M1 Macs using ARM-based version of Homebrew #191

Open cdeyoung opened 3 years ago

cdeyoung commented 3 years ago

Homebrew installs packages on Intel-based Macs into /usr/local. It installs packages on M1-based Macs into /opt/homebrew. The asdf-erlang package currently fails to build support for ODBC (even though the unixodbc package is installed) with the following error:

* odbc : ODBC library - link check failed

I've verified that the library files are linked using the brew link command. I've also tried setting my environment to manually point to the ODBC files in /opt/homebrew, but the asdf-erlang package still can't seem to find the library files on M1 Macs. It works fine on Intel-based Macs.

jeno007 commented 3 years ago

it worked for me: CC="/usr/bin/gcc -I/opt/homebrew/Cellar/unixodbc/2.3.9/include -L/opt/homebrew/Cellar/unixodbc/2.3.9/lib" asdf install erlang 23.2.3

nikneroz commented 3 years ago

@cdeyoung Did you find a way to build it with ODBC support?

nikneroz commented 3 years ago

Hope this will help anyone.

You need to install unixodbc with brew install unixodbc and link it

sudo ln -s /opt/homebrew/Cellar/unixodbc/2.3.9_1/ /usr/local/odbc                                                                                                                        
sudo chown -R $(whoami) /usr/local/odbc/

Add --with-odbc={path_to_unixodbc} to .kerlrc like this

KERL_CONFIGURE_OPTIONS="--enable-darwin-64bit --disable-hipe --enable-vm-probes --with-dynamic-trace=dtrace --disable-native-libs --enable-kernel-poll --enable-threads --enable-smp-support --with-wx --with-odbc=/opt/homebrew/Cellar/unixodbc/2.3.9_1"
GREP_OPTIONS=''

Also we need to set ENVs

export CC="/usr/bin/gcc -I/opt/homebrew/Cellar/unixodbc/2.3.9_1/include"
export LDFLAGS="-L/opt/homebrew/Cellar/unixodbc/2.3.9_1/lib"

After this you can install erlang with asdf install erlang 24.0.3

Stratus3D commented 3 years ago

@cdeyoung did you ever get your build working?

@nikneroz is there anything we should change in the docs or the code to make this easier in the future? PRs welcomed!

cdeyoung commented 3 years ago

@cdeyoung did you ever get your build working?

Sorry for the very late reply, @Stratus3D. I've been down with health issues and just got back to this.

No, I have not compiled Erlang with ODBC support yet on an M1 but I haven't tried @nikneroz's suggestion either. I'll try it.

dylan-chong commented 2 years ago

@nikneroz This didn't work for me (erlang 24.1.7), mac os 12.1 M1 (terminal kitty, in x86 mode)

carlogilmar commented 2 years ago

Worked fine 🚀

I just needed:

  1. Uninstall my Erlang and elixir versions
  2. Install the unixodbc using brew
  3. Link it
  4. Export the variables
  5. Reinstall again Erlang and elixir (in my case)
Johnius commented 2 years ago

What is worked for me: CFLAGS="-O2 -g -I/opt/homebrew/Cellar/unixodbc/2.3.9_1/include" LDFLAGS="-L/opt/homebrew/Cellar/unixodbc/2.3.9_1/lib" ./configure --with-odbc="/opt/homebrew/Cellar/unixodbc/2.3.9_1"

austinarbor commented 2 years ago

@carlogilmar which variables are you referring to in step 4?

jrasanen commented 2 years ago

The environment variables that were mentioned above. Worked for me too.

DavidAntaramian commented 2 years ago

After some testing based on @nikneroz's instructions, I've determined that the following pattern works, at least on Apple Silicon Macs with Erlang 25.0.3 when building using asdf. I've included additional context so that others can understand why this works, and you should be able to use that to adjust the instructions to your needs.

The first expectation is that the ODBC library is installed using Homebrew: brew install unixodbc.

Second, you must link the install directory to /usr/local/odbc. The rest of these instructions will fail if you don't. The following command will link the directory: sudo ln -s $(realpath $(brew --prefix unixodbc)) /usr/local/odbc. The link must be to the actual directory where UnixODBC is installed, and realpath will ensure you get the right location instead of linking to a symlink (which won't work properly).

Then, the following environment variables must be set before triggering the Erlang build system:

export CC="/usr/bin/gcc -I$(brew --prefix unixodbc)/include"
export LDFLAGS="-L$(brew --prefix unixodbc)/lib"

Then, you can build Erlang using whatever build pattern you prefer. For example, I use asdf which in turn depends on kerl.

The configuration depends on the helper command brew --prefix which will output the directory where dependency files can be found. For example, calling brew --prefix unixodbc on an Apple Silicon Mac will output /opt/homebrew/opt/unixodbc.

Autoconf is the program that determines how to configure the Erlang build and as part of that process it will try to detect whether dependency libraries are installed for different features. If the library isn't installed, it disables the feature.

CC explicitly tells Autoconf which C compiler to use. In this case, we tell it to use the GNU Compiler Collection (GCC) front-end and call it with the -I flag. This flag tells GNU GCC that we want to include a non-standard directory in the search path for header files. In this case, we are including the directory where the UnixODBC headers are installed.

LDFLAGS is used to pass additional flags to the ld linker called during the build process. The -L flag instructs ld to look for libraries in a non-standard directory. In this case, we are including the directory where the UnixODBC library is installed. (Note: The referenced documentation is for the GNU linker tool which is part of the GNU Binutils project, but on macOS the Apple LD64 tool will be used instead. The flag is used the same way for both tools.)

Note, you do not need to pass --with-odbc as part of your configuration for the Erlang build. Autoconf will assume that ODBC support should be included as long as it can discover a supporting library.

leandro-cft commented 2 years ago

In my case, sudo ln -s $(realpath $(brew --prefix odbc)) /usr/local/odbc was not working, as brew --prefix odbc returned Error: No available formula with the name "odbc"..

But brew --prefix unixodbc returned a path.

So I just changed it to sudo ln -s $(realpath $(brew --prefix unixodbc)) /usr/local/odbc, and it worked.

Thanks, guys!

DavidAntaramian commented 2 years ago

Thanks @leandro-cft! Edited my instructions with your updates.

noslav commented 1 year ago

Hope this will help anyone.

You need to install unixodbc with brew install unixodbc and link it

sudo ln -s /opt/homebrew/Cellar/unixodbc/2.3.9_1/ /usr/local/odbc                                                                                                                        
sudo chown -R $(whoami) /usr/local/odbc/

Add --with-odbc={path_to_unixodbc} to .kerlrc like this

KERL_CONFIGURE_OPTIONS="--enable-darwin-64bit --disable-hipe --enable-vm-probes --with-dynamic-trace=dtrace --disable-native-libs --enable-kernel-poll --enable-threads --enable-smp-support --with-wx --with-odbc=/opt/homebrew/Cellar/unixodbc/2.3.9_1"
GREP_OPTIONS=''

Also we need to set ENVs

export CC="/usr/bin/gcc -I/opt/homebrew/Cellar/unixodbc/2.3.9_1/include"
export LDFLAGS="-L/opt/homebrew/Cellar/unixodbc/2.3.9_1/lib"

After this you can install erlang with asdf install erlang 24.0.3

Updated instructions

You need to install unixodbc with brew install unixodbc and link it -

sudo ln -sfn $(realpath $(brew --prefix unixodbc)) /usr/local/odbc                                                                                                                  
sudo chown -R $(whoami) /usr/local/odbc/

Add --with-odbc={path_to_unixodbc} to .kerlrc like this

KERL_CONFIGURE_OPTIONS="--enable-darwin-64bit --disable-hipe --enable-vm-probes --with-dynamic-trace=dtrace --disable-native-libs --enable-kernel-poll --enable-threads --enable-smp-support --with-wx --with-odbc=/opt/homebrew/Cellar/unixodbc/2.3.9_1"
GREP_OPTIONS=''

Also we need to set ENVs

export CC="/usr/bin/gcc -I/opt/homebrew/Cellar/unixodbc/2.3.11/include"
export LDFLAGS="-L/opt/homebrew/Cellar/unixodbc/2.3.11/lib"

After this you can install erlang with asdf install erlang 25.1.2

bklebe commented 1 year ago

I didn't like the solution of having to create a symbolic link so I dug deep into the Erlang Makefiles in an attempt to discover the root of this problem.

In short: the Erlang build system doesn't recognize it's building on Darwin in recent versions because it assumes the version string starts with darwin1* and we're now on Darwin 22.5.0 as of Ventura: https://github.com/erlang/otp/blob/f820bad7bed34cc4365bb9cac56eaa84c9a5bddc/lib/odbc/configure.ac#L151-L163

$ uname -a
Darwin <hostname> 22.5.0 Darwin Kernel Version 22.5.0: Mon Apr 24 20:52:24 PDT 2023; root:xnu-8796.121.2~5/RELEASE_ARM64_T6000 arm64

This causes it to fall through to a generic case that looks for ODBC libraries and headers in /usr/local/odbc: https://github.com/erlang/otp/blob/f820bad7bed34cc4365bb9cac56eaa84c9a5bddc/lib/odbc/configure.ac#L204-L206.

It will also check in the directory supplied with --with-odbc as a last resort; this is the key to building without the symbolic link.

I considered submitting a patch to fix this upstream but I really hate fighting with Autotools and I couldn't figure out how to make it work generically, and I don't know what Erlang/OTP's support policy is for older versions of macOS (I typically only care about the latest because I try to upgrade as soon as possible). The build system also expects macOS to ship with libiodbc, which may have been the case for darwin1x but doesn't appear to be the case now, despite being in the open source tree as recently as Ventura 13.2: https://github.com/apple-oss-distributions/distribution-macOS/tree/macos-132. I appear to have a libiodbc dylib supplied as part of a Rapid Security Response (https://support.apple.com/en-us/HT201224) but it doesn't include headers so it's not really relevant here.

So in conclusion, to build without linking unixodbc, you can set these environment variables after installing unixodbc (I put them in .zshenv, but your choice ultimately):

export CPPFLAGS="${CPPFLAGS+"$CPPFLAGS "}-I/opt/homebrew/opt/unixodbc/include"
export LDFLAGS="${LDFLAGS+"$LDFLAGS "}-L/opt/homebrew/opt/unixodbc/lib"
export KERL_CONFIGURE_OPTIONS="--with-odbc=/opt/homebrew/opt/unixodbc"

Ironically, I've still yet to use the ODBC support in Erlang and Elixir, I just hate build errors and having "incomplete" Erlang runtime installs hanging around.