cs50 / libcs50

This is CS50's Library for C.
https://cs50.readthedocs.io/libraries/cs50/c/
GNU General Public License v3.0
1.74k stars 856 forks source link

Mac M1: Undefined symbols for architecture arm64 when trying to use cs50.h #334

Open rob-scheepens opened 2 weeks ago

rob-scheepens commented 2 weeks ago

@zizlog @HoonyHoney-91: as follow-up to:

I don't think it solves the issue. Although it works using your suggestion, it fails using make, giving the error @HoonyHoney-91 points out. I'm having the same issue as him.

Originally posted by @zizlog in https://github.com/cs50/libcs50/issues/212#issuecomment-1516497958

On my Mac M1 I got a similar error message:

rob@TJYV4J34RJ ~ % make hello
cc     hello.c   -o hello
Undefined symbols for architecture arm64:
  "_get_string", referenced from:
      _main in hello-f3db2a.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [hello] Error 1

The mention of clang made me suspicious, as I was under the impression that gcc was being used. When running gcc indeed a reference to clang comes up:

rob@TJYV4J34RJ ~ % gcc
clang: error: no input files

Digging a bit led me to https://stackoverflow.com/questions/64992467/mac-clang-installation-seems-to-override-gcc-install. The comments in there made me check the version of make I was using:

rob@TJYV4J34RJ ~ % /usr/bin/make -v
GNU Make 3.81
Copyright (C) 2006  Free Software Foundation, Inc.

That seemed pretty ancient, checking the versions on https://ftp.gnu.org/gnu/make/. After running "brew install make", I now got:

rob@TJYV4J34RJ ~ % make -v
GNU Make 4.4.1
Built for x86_64-apple-darwin23.4.0
Copyright (C) 1988-2023 Free Software Foundation, Inc.

Seeing this caveat made me run "export PATH="/usr/local/opt/make/libexec/gnubin:$PATH"":

==> Caveats
GNU "make" has been installed as "gmake".
If you need to use it as "make", you can add a "gnubin" directory
to your PATH from your bashrc like:

    PATH="/usr/local/opt/make/libexec/gnubin:$PATH"

Now, when running "make hello" it works, without having to add anything special to link cs50 as make now invokes gcc with the right parameters, just like when using a Makefile:

rob@TJYV4J34RJ ~ % make hello 
gcc -Wall -Wextra -std=c11 -o hello hello.c -lcs50
rob@TJYV4J34RJ ~ % 
szchelkowski commented 1 week ago

I think the issues on M1 Macs may not stem from the system installation of Clang, since I have now tried the following:

> make -v
GNU Make 4.4.1
Built for x86_64-apple-darwin24.0.0
Copyright (C) 1988-2023 Free Software Foundation, Inc.
> make hello CC=cc  
cc     hello.c   -o hello
Undefined symbols for architecture x86_64:
  "_get_string", referenced from:
      _main in hello-30e0df.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [<builtin>: hello] Error 1
> make hello CC=gcc
gcc     hello.c   -o hello
Undefined symbols for architecture x86_64:
  "_get_string", referenced from:
      _main in hello-65c5b8.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [<builtin>: hello] Error 1
> make hello CC=gcc-14
gcc-14     hello.c   -o hello
Undefined symbols for architecture x86_64:
  "_get_string", referenced from:
      _main in cc8pb4H9.o
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status
make: *** [<builtin>: hello] Error 1

gcc-14 is a Homebrew installation (instead of regular gcc, which just uses clang):

> gcc-14 -v
Using built-in specs.
COLLECT_GCC=gcc-14
COLLECT_LTO_WRAPPER=/usr/local/Cellar/gcc/14.2.0/bin/../libexec/gcc/x86_64-apple-darwin23/14/lto-wrapper
Target: x86_64-apple-darwin23
Configured with: ../configure --prefix=/usr/local/opt/gcc --libdir=/usr/local/opt/gcc/lib/gcc/current --disable-nls --enable-checking=release --with-gcc-major-version-only --enable-languages=c,c++,objc,obj-c++,fortran,m2 --program-suffix=-14 --with-gmp=/usr/local/opt/gmp --with-mpfr=/usr/local/opt/mpfr --with-mpc=/usr/local/opt/libmpc --with-isl=/usr/local/opt/isl --with-zstd=/usr/local/opt/zstd --with-pkgversion='Homebrew GCC 14.2.0' --with-bugurl=https://github.com/Homebrew/homebrew-core/issues --with-system-zlib --build=x86_64-apple-darwin23 --with-sysroot=/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 14.2.0 (Homebrew GCC 14.2.0)

...and, for good measure (and as a last resort), I tried compiling with zig, too:

> zig cc -o hello hello.c -target aarch64-macos-none
error: undefined symbol: _get_string
    note: referenced by /Users/../.cache/zig/o/add84b2a83bc8c83334ef31d90e138d2/hello.o:_main

Edit: @rob-scheepens I was able to compile hello.c using clang's gcc, but I had to specify cs50.c, like so:

> gcc -g -o hello hello.c ../libcs50/src/cs50.c

...but also Homebrew's gcc-14 works just fine in similar manner:

> gcc-14 -g -o hello hello.c ../libcs50/src/cs50.c

Running clang on the file with the verbose (-v) flag, gives a bit more context:

clang hello.c -v
Apple clang version 16.0.0 (clang-1600.0.26.3)
Target: arm64-apple-darwin24.0.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
 "/Library/Developer/CommandLineTools/usr/bin/clang" -cc1 -triple arm64-apple-macosx15.0.0 -Wundef-prefix=TARGET_OS_ -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -Werror=implicit-function-declaration -emit-obj -mrelax-all -dumpdir a- -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name hello.c -mrelocation-model pic -pic-level 2 -mframe-pointer=non-leaf -fno-strict-return -ffp-contract=on -fno-rounding-math -funwind-tables=1 -fobjc-msgsend-selector-stubs -target-sdk-version=15.0 -fvisibility-inlines-hidden-static-local-var -fno-modulemap-allow-subdirectory-search -target-cpu apple-m1 -target-feature +v8.5a -target-feature +aes -target-feature +crc -target-feature +dotprod -target-feature +fp-armv8 -target-feature +fp16fml -target-feature +lse -target-feature +ras -target-feature +rcpc -target-feature +rdm -target-feature +sha2 -target-feature +sha3 -target-feature +neon -target-feature +zcm -target-feature +zcz -target-feature +fullfp16 -target-abi darwinpcs -debugger-tuning=lldb -target-linker-version 1115.7.3 -v -fcoverage-compilation-dir=/Users/szch/cs50/lecture_1_-_c -resource-dir /Library/Developer/CommandLineTools/usr/lib/clang/16 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -I/opt/homebrew/include -I/usr/local/include -internal-isystem /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/local/include -internal-isystem /Library/Developer/CommandLineTools/usr/lib/clang/16/include -internal-externc-isystem /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include -internal-externc-isystem /Library/Developer/CommandLineTools/usr/include -Wno-reorder-init-list -Wno-implicit-int-float-conversion -Wno-c99-designator -Wno-final-dtor-non-final-class -Wno-extra-semi-stmt -Wno-misleading-indentation -Wno-quoted-include-in-framework-header -Wno-implicit-fallthrough -Wno-enum-enum-conversion -Wno-enum-float-conversion -Wno-elaborated-enum-base -Wno-reserved-identifier -Wno-gnu-folding-constant -fdebug-compilation-dir=/Users/szch/cs50/lecture_1_-_c -ferror-limit 19 -stack-protector 1 -fstack-check -mdarwin-stkchk-strong-link -fblocks -fencode-extended-block-signature -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fmax-type-align=16 -fcommon -fcolor-diagnostics -clang-vendor-feature=+disableNonDependentMemberExprInCurrentInstantiation -fno-odr-hash-protocols -clang-vendor-feature=+enableAggressiveVLAFolding -clang-vendor-feature=+revert09abecef7bbf -clang-vendor-feature=+thisNoAlignAttr -clang-vendor-feature=+thisNoNullAttr -clang-vendor-feature=+disableAtImportPrivateFrameworkInImplementationError -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /var/folders/6s/mtsq965d07j5400vpbs74dq40000gn/T/hello-2e96bd.o -x c hello.c
clang -cc1 version 16.0.0 (clang-1600.0.26.3) default target arm64-apple-darwin24.0.0
ignoring nonexistent directory "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/local/include"
ignoring nonexistent directory "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/Library/Frameworks"
#include "..." search starts here:
#include <...> search starts here:
 /opt/homebrew/include
 /usr/local/include
 /Library/Developer/CommandLineTools/usr/lib/clang/16/include
 /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include
 /Library/Developer/CommandLineTools/usr/include
 /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks (framework directory)
End of search list.
 "/Library/Developer/CommandLineTools/usr/bin/ld" -demangle -lto_library /Library/Developer/CommandLineTools/usr/lib/libLTO.dylib -no_deduplicate -dynamic -arch arm64 -platform_version macos 15.0.0 15.0 -syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -mllvm -enable-linkonceodr-outlining -o a.out -L/opt/homebrew/lib -L/usr/local/lib /var/folders/6s/mtsq965d07j5400vpbs74dq40000gn/T/hello-2e96bd.o -lSystem /Library/Developer/CommandLineTools/usr/lib/clang/16/lib/darwin/libclang_rt.osx.a
Undefined symbols for architecture arm64:
  "_get_string", referenced from:
      _main in hello-2e96bd.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

...which I find a bit spooky and confusing, because I do have the cs50.h file in the second listed search directory /usr/local/include:

/usr/local/include via C v16.0.0-clang
> find . -name "*cs50*"
./cs50.h