Home > database >  Why Do I need to compile C file referencing #include <semaphore.h> with -lpthread in Ubuntu 20
Why Do I need to compile C file referencing #include <semaphore.h> with -lpthread in Ubuntu 20

Time:01-21

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.

  • Related