Bug 255123

Summary: devel/cmake: CMAKE_HAVE_LIBC_PTHREAD fails building projects: ld: error: undefined symbol: pthread_create
Product: Ports & Packages Reporter: Mohammad S. Babaei <info>
Component: Individual Port(s)Assignee: freebsd-kde (group) <kde>
Status: Closed Works As Intended    
Severity: Affects Some People CC: adridg, kde, lbartoletti, pavelivolkov, tcberner
Priority: --- Keywords: needs-qa
Version: LatestFlags: tcberner: maintainer-feedback+
Hardware: Any   
OS: Any   

Description Mohammad S. Babaei 2021-04-16 14:27:55 UTC
I have a few cmake-based C++ projects, which fail to build on 12.2 and 13.0. They used to work on earlier versions of FreeBSD:

$ cat build/CMakeFiles/CMakeError.log

Performing C SOURCE FILE Test CMAKE_HAVE_LIBC_PTHREAD failed with the following output:
Change Dir: /home/mamadou/barandazstorm/build/CMakeFiles/CMakeTmp

Run Build Command(s):/usr/local/bin/ninja cmTC_cea33 && [1/2] Building C object CMakeFiles/cmTC_cea33.dir/src.c.o
[2/2] Linking C executable cmTC_cea33
FAILED: cmTC_cea33 
: && /usr/bin/cc   CMakeFiles/cmTC_cea33.dir/src.c.o -o cmTC_cea33   && :
ld: error: undefined symbol: pthread_create
>>> referenced by src.c
>>>               CMakeFiles/cmTC_cea33.dir/src.c.o:(main)
cc: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.


Source file was:
#include <pthread.h>

static void* test_func(void* data)
{
  return data;
}

int main(void)
{
  pthread_t thread;
  pthread_create(&thread, NULL, test_func, NULL);
  pthread_detach(thread);
  pthread_cancel(thread);
  pthread_join(thread, NULL);
  pthread_atfork(NULL, NULL, NULL);
  pthread_exit(NULL);

  return 0;
}

Determining if the backtrace exist failed with the following output:
Change Dir: /home/mamadou/barandazstorm/build/CMakeFiles/CMakeTmp

Run Build Command(s):/usr/local/bin/ninja cmTC_1559d && [1/2] Building C object CMakeFiles/cmTC_1559d.dir/CheckSymbolExists.c.o
[2/2] Linking C executable cmTC_1559d
FAILED: cmTC_1559d 
: && /usr/bin/cc   CMakeFiles/cmTC_1559d.dir/CheckSymbolExists.c.o -o cmTC_1559d   && :
ld: error: undefined symbol: backtrace
>>> referenced by CheckSymbolExists.c
>>>               CMakeFiles/cmTC_1559d.dir/CheckSymbolExists.c.o:(main)
cc: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.


File /home/mamadou/barandazstorm/build/CMakeFiles/CMakeTmp/CheckSymbolExists.c:
/* */
#include <execinfo.h>

int main(int argc, char** argv)
{
  (void)argv;
#ifndef backtrace
  return ((int*)(&backtrace))[argc];
#else
  (void)argc;
  return 0;
#endif
}


Here is how Threads are being enabled and used:

set(THREADS_PREFER_PTHREAD_FLAG TRUE)
find_package(Threads REQUIRED)

target_link_libraries(bbackend
    PRIVATE
    ${libzmq_LIBRARIES}
    Threads::Threads
)

There is a similar thread for databases/sqlite3, but I am not sure how these changes affect cmake-based projects on FreeBSD?
Comment 1 Mohammad S. Babaei 2021-04-16 14:29:02 UTC
Sorry, forgot to mention the thread
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=244459
Comment 2 Adriaan de Groot freebsd_committer freebsd_triage 2021-04-23 21:59:24 UTC
I bumped CMake just this week, can you double-check if this problem persists? I seem to remember seeing some pthread fallout, which I *probably* fixed before landing it -- but I also probably missed some cases.

It'd be really useful to attach a tarball to this PR with a complete example.
Comment 3 Mohammad S. Babaei 2021-04-24 12:22:37 UTC
I just tested it, and the results are the same:

Performing C SOURCE FILE Test CMAKE_HAVE_LIBC_PTHREAD failed with the following output:
Change Dir: /home/mamadou/blog-subscription-service/build/CMakeFiles/CMakeTmp

Run Build Command(s):/usr/local/bin/ninja cmTC_e063f && [1/2] Building C object CMakeFiles/cmTC_e063f.dir/src.c.o
[2/2] Linking C executable cmTC_e063f
FAILED: cmTC_e063f 
: && /usr/bin/cc   CMakeFiles/cmTC_e063f.dir/src.c.o -o cmTC_e063f   && :
ld: error: undefined symbol: pthread_create
>>> referenced by src.c
>>>               CMakeFiles/cmTC_e063f.dir/src.c.o:(main)
cc: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.


Source file was:
#include <pthread.h>

static void* test_func(void* data)
{
  return data;
}

int main(void)
{
  pthread_t thread;
  pthread_create(&thread, NULL, test_func, NULL);
  pthread_detach(thread);
  pthread_cancel(thread);
  pthread_join(thread, NULL);
  pthread_atfork(NULL, NULL, NULL);
  pthread_exit(NULL);

  return 0;
}
Comment 4 Mohammad S. Babaei 2021-04-24 12:35:35 UTC
This is the simplest program I can reproduce it with:

$ cat main.cpp

int main()
{
	return 0
}


$ cat CMakeLists.txt

cmake_minimum_required(VERSION 3.14...3.20)

project(Barandazstorm
    VERSION 0.0.0
    DESCRIPTION "A Twitter analysis tool dedicated to #IranRegimeChange"
    HOMEPAGE_URL "https://twitter.com/Barandazstorm"
    LANGUAGES C CXX
)

set(THREADS_PREFER_PTHREAD_FLAG TRUE)
find_package(Threads REQUIRED)

add_executable(hello main.cpp)

target_link_libraries(hello
    PRIVATE
    Threads::Threads
)


$ cmake -GNinja -S . -B build

-- The C compiler identification is Clang 10.0.1
-- The CXX compiler identification is Clang 10.0.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Failed
-- Check if compiler accepts -pthread
-- Check if compiler accepts -pthread - yes
-- Found Threads: TRUE  
-- Configuring done
-- Generating done
-- Build files have been written to: /usr/home/mamadou/test-cmake/build


$ cat build/CMakeFiles/CMakeError.log

Performing C SOURCE FILE Test CMAKE_HAVE_LIBC_PTHREAD failed with the following output:
Change Dir: /usr/home/mamadou/test-cmake/build/CMakeFiles/CMakeTmp

Run Build Command(s):/usr/local/bin/ninja cmTC_230ca && [1/2] Building C object CMakeFiles/cmTC_230ca.dir/src.c.o
[2/2] Linking C executable cmTC_230ca
FAILED: cmTC_230ca 
: && /usr/bin/cc   CMakeFiles/cmTC_230ca.dir/src.c.o -o cmTC_230ca   && :
ld: error: undefined symbol: pthread_create
>>> referenced by src.c
>>>               CMakeFiles/cmTC_230ca.dir/src.c.o:(main)
cc: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.


Source file was:
#include <pthread.h>

static void* test_func(void* data)
{
  return data;
}

int main(void)
{
  pthread_t thread;
  pthread_create(&thread, NULL, test_func, NULL);
  pthread_detach(thread);
  pthread_cancel(thread);
  pthread_join(thread, NULL);
  pthread_atfork(NULL, NULL, NULL);
  pthread_exit(NULL);

  return 0;
}
Comment 5 Loïc Bartoletti freebsd_committer freebsd_triage 2021-05-05 19:44:55 UTC
I think it's a false positive.

cmake use FindThreads module to determine how to build thread program.

First it searches pthread.h https://gitlab.kitware.com/cmake/cmake/-/blob/d6da6784bfdb59456942d11d476593906945adbb/Modules/FindThreads.cmake#L144

> -- Looking for pthread.h
> -- Looking for pthread.h - found

We have pthread.h, so how to link it? With  -lpthread, -lpthread, -lthread or  libc?

This part, and this is the test in the CMakeError.log file, is not for us.
 
CMake will
> Check if pthread functions are in normal C library.
> We list some pthread functions in PTHREAD_C_CXX_TEST_SOURCE test code.
> If the pthread functions already exist in C library, we could just use
> them instead of linking to the additional pthread library.

From https://gitlab.kitware.com/cmake/cmake/-/blob/d6da6784bfdb59456942d11d476593906945adbb/Modules/FindThreads.cmake#L158-166 

> -- Performing Test CMAKE_HAVE_LIBC_PTHREAD
> -- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Failed

So, CMake will check with pthread, https://gitlab.kitware.com/cmake/cmake/-/blob/d6da6784bfdb59456942d11d476593906945adbb/Modules/FindThreads.cmake#L171-177

-- Check if compiler accepts -pthread
-- Check if compiler accepts -pthread - yes

It found pthread.h and libpthread, we can build the code.
Comment 6 Kubilay Kocak freebsd_committer freebsd_triage 2021-05-07 06:01:31 UTC
^Triage: Correct value in maintainer-feedback
Comment 7 Adriaan de Groot freebsd_committer freebsd_triage 2022-05-02 16:23:53 UTC
The errors being written to CMakeErrors.log during cmake-time are **also** from the tests being run to determine what works and what doesn't. So there's no harm in there being errors in there: for instance, determining whether a function strblep() exists will fail and leave an error in that log -- it just means strblep() doesn't exist. If the compilation of target code **after** cmake-time fails because of strblep(), then it's a bug in the target code: it shouldn't be using it if it wasn't found.

So these entries in the log don't indicate there is a problem. So I'm going to close this as "doesn't show an actual problem". Maybe there **is** a pthreads-using program that does not work, but the suggested minimal main isn't it.

Changing main to this:

```
#include <pthread.h>
int main(){
  return pthread_create(nullptr, nullptr, nullptr,nullptr);
}
```

Will compile and link (passing `-pthread` to the compiler / linker).