being relatively new to C development I am puzzled about a problem in our CI build. I can perfectly compile a piece of C-Code using semaphores, that I found here https://gist.github.com/junfenglx/7412986 (and copied below) and save as semaphores.c
It compiles perfectly fine on my host Ubuntu system just using 'gcc semaphores.c'. Now, I try to compile it inside a docker container based on ubuntu (maven:3.8.6-eclipse-temurin-19-focal) started with docker run --rm -it --ipc=private -v ${PWD}:/opt/project maven:3.8.6-eclipse-temurin-19-focal /bin/bash
. I first have to install some stuff with apt-get update && apt-get install build-essential glibc-source libc6-dev
.
Then I have to compile the same file with gcc semaphores.c -lpthread
, otherwise I end up with errors
root@b76fe0a09bda:/opt/project# gcc semaphores.c /usr/bin/ld: /tmp/ccRGoNcc.o: in function `main': semaphores.c:(.text 0x140): undefined reference to `sem_open' /usr/bin/ld: semaphores.c:(.text 0x150): undefined reference to `sem_unlink' /usr/bin/ld: semaphores.c:(.text 0x208): undefined reference to `sem_destroy' /usr/bin/ld: semaphores.c:(.text 0x231): undefined reference to `sem_wait' /usr/bin/ld: semaphores.c:(.text 0x2ac): undefined reference to `sem_post' collect2: error: ld returned 1 exit status
I can not figure out, what exactly is different inside the docker container and on my host system. Can you help me to understand whats going on?
EDIT With ssbssa answer I figured out, that the difference in GCC behavior is a result of the Ubuntu version 20.04 Vs 22.04. So I would like to rephrase the question a bit. Is the difference between the systems just a configuration change somewhere? If so, how would I adjust it to build on 20.04 without explicitly pointing to the libraries? Or is there something more fundamentally changed e.g. on the gcc compiler?
The content of the semaphores.c file
#include <stdio.h> /* printf() */
#include <stdlib.h> /* exit(), malloc(), free() */
#include <unistd.h>
#include <sys/types.h> /* key_t, sem_t, pid_t */
#include <sys/wait.h>
#include <sys/shm.h> /* shmat(), IPC_RMID */
#include <errno.h> /* errno, ECHILD */
#include <semaphore.h> /* sem_open(), sem_destroy(), sem_wait().. */
#include <fcntl.h> /* O_CREAT, O_EXEC */
// Sample from https://gist.github.com/junfenglx/7412986
// In Ubuntu container, compile with: gcc semaphores.c -pthread
int main (int argc, char **argv){
int i; /* loop variables */
key_t shmkey; /* shared memory key */
int shmid; /* shared memory id */
sem_t *sem; /* synch semaphore *//*shared */
pid_t pid; /* fork pid */
int *p; /* shared variable *//*shared */
unsigned int n; /* fork count */
unsigned int value; /* semaphore value */
/* initialize a shared variable in shared memory */
shmkey = ftok ("/dev/null", 5); /* valid directory name and a number */
printf ("shmkey for p = %d\n", shmkey);
shmid = shmget (shmkey, sizeof (int), 0644 | IPC_CREAT);
if (shmid < 0){ /* shared memory error check */
perror ("shmget\n");
exit (1);
}
p = (int *) shmat (shmid, NULL, 0); /* attach p to shared memory */
*p = 0;
printf ("p=%d is allocated in shared memory.\n\n", *p);
/********************************************************/
printf ("How many children do you want to fork?\n");
printf ("Fork count: ");
scanf ("%u", &n);
printf ("What do you want the semaphore value to be?\n");
printf ("Semaphore value: ");
scanf ("%u", &value);
/* initialize semaphores for shared processes */
sem = sem_open ("pSem", O_CREAT | O_EXCL, 0644, value);
/* name of semaphore is "pSem", semaphore is reached using this name */
sem_unlink ("pSem");
/* unlink prevents the semaphore existing forever */
/* if a crash occurs during the execution */
printf ("semaphores initialized.\n\n");
/* fork child processes */
for (i = 0; i < n; i ){
pid = fork ();
if (pid < 0) /* check for error */
printf ("Fork error.\n");
else if (pid == 0)
break; /* child processes */
}
/******************************************************/
/****************** PARENT PROCESS ****************/
/******************************************************/
if (pid != 0){
/* wait for all children to exit */
while (pid = waitpid (-1, NULL, 0)){
if (errno == ECHILD)
break;
}
printf ("\nParent: All children have exited.\n");
/* shared memory detach */
shmdt (p);
shmctl (shmid, IPC_RMID, 0);
/* cleanup semaphores */
printf("sem_destroy return value:%d\n",sem_destroy (sem));
exit (0);
}
/******************************************************/
/****************** CHILD PROCESS *****************/
/******************************************************/
else{
sem_wait (sem); /* P operation */
printf (" Child(%d) is in critical section.\n", i);
sleep (1);
*p = i % 3; /* increment *p by 0, 1 or 2 based on i */
printf (" Child(%d) new value of *p=%d.\n", i, *p);
sem_post (sem); /* V operation */
exit (0);
}
}
/*src:http://stackoverflow.com/a/16400833*/
CodePudding user response:
Why Do I need to compile C file referencing #include <semaphore.h>
Nitpick: There is no need for -lpthread
when including semaphore.h. There is a need when using an external symbol that is declared in that header.
with -lpthread in Ubuntu 20.04, but not on Ubuntu 22.04?
Because glibc version changed. The reason is this commit https://github.com/bminor/glibc/commit/0b7d48d1062e4383b4a78e0bb78c5f0f29479780 . You can read https://developers.redhat.com/articles/2021/12/17/why-glibc-234-removed-libpthread .
Still, for portability with systems with "older" glibc, you should just use -lpthread
always.