0

Below error occurs while I was writing two functions xxxx as part of uni work. The IDE I'm using is Visual Studio Code.

The problem was that when I tried to compile a single file in the folder code/myIO, it threw an error:

(I've replaced the folder's path with ($). I promise the problem wasn't there)

cd ($) && clang++ r.cpp -o ($)/r -D LOCAL -Wall -O2 -fsanitize=undefined

Undefined symbols for architecture arm64:
  "_Tp::INT", referenced from:
      split(char const*, _Tp*) in r-ebf422.o
  "_Tp::fmt", referenced from:
      split(char const*, _Tp*) in r-ebf422.o
  "_Tp::str", referenced from:
      split(char const*, _Tp*) in r-ebf422.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

What's more, when I tried to link some files, similar error happened.

clang++ -shared -o libmystdio.so myscanf.o myprintf.o
Undefined symbols for architecture arm64:
  "_Tp::INT", referenced from:
      split(char const*, _Tp*) in myscanf.o
      split(char const*, _Tp*) in myprintf.o
  "_Tp::fmt", referenced from:
      split(char const*, _Tp*) in myscanf.o
      split(char const*, _Tp*) in myprintf.o
  "_Tp::str", referenced from:
      split(char const*, _Tp*) in myscanf.o
      split(char const*, _Tp*) in myprintf.o
  "_Tp::LONG", referenced from:
      split(char const*, _Tp*) in myscanf.o
      split(char const*, _Tp*) in myprintf.o
  "_Tp::LONGLONG", referenced from:
      split(char const*, _Tp*) in myscanf.o
      split(char const*, _Tp*) in myprintf.o
  "_out_buf", referenced from:
      myprintf(char const*, ...) in myprintf.o
  "_out_idx", referenced from:
      myprintf(char const*, ...) in myprintf.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [libmystdio.so] Error 1

In case you wonder what I've written, please click here. However it's not finished,I doubt you would be interested...(I made a few comments and most of them are in Chinese, for my groupmates to read)

And, files in folder code aren't affected. They can be compiled and run normally.Only those in folder code/myIO went wrong.

Here's my clang++ version:

clang++ -v
Apple clang version 12.0.5 (clang-1205.0.22.11)
Target: arm64-apple-darwin20.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

Thanks for your help in advance!

TiroxWater
  • 3
  • 1
  • 3
  • 1
    Does this answer your question? [What is an undefined reference/unresolved external symbol error and how do I fix it?](https://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix) If not, please update your question with details that will distinguish your issue from what the other question covers. A [mre] would help, just make sure it reproduces the error message and comes with an explanation of why you believe the error message is wrong. – JaMiT Dec 10 '21 at 03:41

1 Answers1

0

You have a declaration without a definition.

utilities.h has:

class _Tp {
  // [...]
public:
  // [...]
  static const int INT = 1, SHORT = 2, LONG = 3, LONGLONG = 4,
      FLOAT = 10, DOUBLE = 11, LONGDOUBLE = 12;

That declares _Tp::INT etc. with initializers, but does not define them. If you ODR-use these values then you need to have a definition for them, meaning that there needs to be a single place designated to hold the bytes of memory for these constants in your program.[0]

The normal way to do this is to have a matching utilities.cpp with:

const int _Tp::INT;
const int _Tp::SHORT;
const int _Tp::LONG;
const int _Tp::LONGLONG;
const int _Tp::FLOAT;
const int _Tp::DOUBLE;
const int _Tp::LONGDOUBLE;

but in your case you might want to consider switching to an enum! To do that you would write in utilities.h:

class _Tp {
  // [...]
public:
  // [...]
  enum { INT = 1, SHORT = 2, LONG = 3, LONGLONG = 4,
      FLOAT = 10, DOUBLE = 11, LONGDOUBLE = 12 };

then you don't need a utilities.cpp.

[0] There's a special-case for allowing values of integral types to be ODR-used without being defined in narrow circumstances, but I recommend that programmers not rely on it. A non-expert makes a innocent change to the code and gets a confusing link error.

Nick Lewycky
  • 1,182
  • 6
  • 14
  • It did work! I can compile r.cpp now. – TiroxWater Dec 10 '21 at 05:42
  • Great to hear it!! – Nick Lewycky Dec 10 '21 at 06:59
  • Sorry for troubling you again, but when I fixed those problems in the project files and build it again, errors about "_out_buf" and "_out_idx" remained. Confusingly, I have not define an variable or function with this name.In fact, "out_buf" and "out_idx" were defined in **main.cpp**, and `extern char out_buf[]` and `extern int out_idx` have been added in **myprintf.cpp**. I asked my instructor about that, but he failed to figure out why. – TiroxWater Dec 11 '21 at 02:22
  • The leading `_` is always present on Mac, that's just part of the platform ABI for C and C++ code. Your variable and function names when compiled through clang or gcc on Mac will be prefixed with an `_` in the object file. The reason it doesn't link is probably the "libmystdio.so" rule in the makefile which attempts to combine `myprintf.o` into a shared object (note, on Mac should be named `.dylib`) without including the main.cpp where is where you define `out_buf` and `out_idx`. – Nick Lewycky Dec 11 '21 at 19:36