Search code examples
c++openmpnew-operatorclang++c++23

How to resolve 'weak-def symbol not found' error run-time error for a C++23 program that uses std::println and omp?


Using std::print with OpenMP results in a runtime error and I am not sure which path to take in resolving the issue. Consider the code below:

/// clang++ -fopenmp -std=c++23 -Wall -Wextra -Werror -g hello.cpp -o hello
#include <iostream>
#include <print>  // C++23, not available in g++; use clang++
using namespace std;
int main(void) {
  #pragma omp parallel
  {
    // cout << "Hello, world.\n"; // works fine
    println("Hello, world");      // results in runtime error
  }

  #pragma omp critical
  return 0;
}

If run the binary, I get:

dyld[65564]: weak-def symbol not found '__ZnwmSt19__type_descriptor_t'weak-def symbol not found '__ZnamSt19__type_descriptor_t'
Abort trap: 6

That translates to not finding:

$ echo __ZnwmSt19__type_descriptor_t | c++filt
operator new(unsigned long, std::__type_descriptor_t)

The same program runs fine if I comment out println and uncomment the line that uses cout:

$ clang++ -fopenmp -std=c++23 -Wall -Wextra -Werror -g hello.cpp -o hello
$ ./hello
Hello, world.
Hello, world.
Hello, world.
Hello, world.
Hello, world.
Hello, world.
Hello, world.
Hello, world.
Hello, world.
Hello, world.
Hello, world.
Hello, world.

The closest hint I got from googling is pointing at some explicit instantiation gone wrong (??)

I then looked into <print> header file and I am unable to spot anything that stands out.

The last thing of interest is that the program size when using std::println is much larger than with std::cout. But the dynamic libraries that the program links to are the same.

# with std::cout
$ ls -lh ./hello
-rwxr-xr-x  1 stacker  staff    42K Mar 31 18:05 ./hello

$ otool -L ./hello
./hello:
        /opt/local/lib/libomp/libomp.dylib (compatibility version 5.0.0, current version 5.0.0)
        @rpath/libc++.1.dylib (compatibility version 1.0.0, current version 1.0.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1336.61.1)

# with std::println
$ ls -lh ./hello
-rwxr-xr-x  1 stacker  staff   354K Mar 31 18:04 ./hello

$ otool -L ./hello
./hello:
        /opt/local/lib/libomp/libomp.dylib (compatibility version 5.0.0, current version 5.0.0)
        @rpath/libc++.1.dylib (compatibility version 1.0.0, current version 1.0.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1336.61.1)

Short of moving back to using standard streams in a fairly large program, I am looking for thoughts and guidance on which way to go? i.e., go to the clang++ folks or the openmp folks. The non-standard operator new suggests to me that perhaps I should pursue this as an openmp issue, but I am not sure.

Thoughts?

Adding clang++ information, and compilation without -fopenmp:

# installed using macports
$ clang++ --version
clang version 17.0.6
Target: x86_64-apple-darwin23.3.0
Thread model: posix
InstalledDir: /opt/local/libexec/llvm-17/bin

Without -fopenmp option both cout and println work fine; note the openmp pragmas are simply ignored without this option:

#include <iostream>
#include <print>  // C++23, not available in g++; use clang++
using namespace std;
int main(void) {
  #pragma omp parallel
  {
    cout << "Hello, world. (using cout)\n"; // works fine
    println("Hello, world. (using println)");      // results in runtime error
  }

  #pragma omp critical
  return 0;
}
$ clang++ -std=c++23 -Wall -Wextra -Werror -g hello.cpp -o hello
$ ./hello
Hello, world. (using cout)
Hello, world. (using println)

Solution

  • Update: Happy to report that the issue is resolved with the latest libomp, clang-18, llvm-18.

    port installed llvm-18 clang-18 libomp
    The following ports are currently installed:
      clang-18 @18.1.7_0+analyzer (active)
      libomp @18.1.6_0 (active)
      llvm-18 @18.1.7_0 (active)
    

    And compiling with -rpath option to find the correct libc++.1.dylib on Mac.

    clang++ -fopenmp -std=c++23 -Wall -Wextra -Werror -g hello.cpp -o hello -rpath /opt/local/libexec/llvm-18/lib
    
    ./hello
    Hello, world
    Hello, world
    Hello, world
    Hello, world
    Hello, world
    Hello, world
    Hello, world
    Hello, world
    Hello, world
    Hello, world
    Hello, world
    Hello, world
    

    And here is the complete sample code for reference.

    // clang++ -fopenmp -std=c++23 -Wall -Wextra -Werror -g hello.cpp -o hello -rpath /opt/local/libexec/llvm-18/lib
    #include <print>  // C++23, use clang++; not available in gcc13 and lower
    using namespace std;
    int main(void) {
      #pragma omp parallel
      {
        println("Hello, world"); // works in clang-18!!!
      }
    
      #pragma omp critical
      return 0;
    }
    

    C++ with OpenMP rules! Just give the process of open source some time to cook :-)