When I compile my C program with make I get an error. I've been developing this project for a few days now and everything compiled fine until I needed to add an external file (semaphore_v2.h). I don't know if I'm importing it incorrectly or what but when I try to compile the project with it it doesn't compile. Some info below.
PD: If the warning "__USE_XOPEN" redefined is the cause I don't know how to fix it. The other error undefined reference to `fmin', can be ignored, I know how to solve that.
I've already checked that the guards of the .h files. I've also checked that I don't inlcude multiple times and that I don't include .c files. I'm guessing that the error must be from the warning that I don't know how to solve or that I made a mistake updating the makefile and I'm not seeing it.
Make error (I've included the verbose mode where the error happens):
> gcc -c bowman.c -gdb -Wall -Wextra
> gcc -c utils.c -gdb -Wall -Wextra
> gcc bowman.o utils.o -o bowman -ggdb -Wall -Wextra
> gcc -c poole.c -ggdb -Wall -Wextra -lpthread
> In file included from request_queue.h:7,
> from poole.c:8:
> semaphore_v2.h:19: warning: "__USE_XOPEN" redefined
> 19 | #define __USE_XOPEN
>
> In file included from /usr/include/x86_64-linux-gnu/bits/libc-header-start.h:33,
> from /usr/include/stdio.h:27,
> from poole.c:3:
> /usr/include/features.h:355: note: this is the location of the previous definition
> 355 | # define __USE_XOPEN 1
>
> poole.c: In function ‘worker’:
> poole.c:26:20: warning: unused parameter ‘args’ [-Wunused-parameter]
> 26 | void *worker(void *args){
> | ~~~~~~^~~~
> poole.c: In function ‘process_new_bowman’:
> poole.c:159:30: warning: unused parameter ‘data’ [-Wunused-parameter]
> 159 | int process_new_bowman(char *data, int fd){
> | ~~~~~~^~~~
> gcc -c request_queue.c -ggdb -Wall -Wextra -lpthread
> gcc -v poole.o utils.o request_queue.o -o poole -ggdb -Wall -Wextra -lpthread
> Using built-in specs.
> COLLECT_GCC=gcc
> COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/11/lto-wrapper
> OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa
> OFFLOAD_TARGET_DEFAULT=1
> Target: x86_64-linux-gnu
> Configured with: ../src/configure -v --with-pkgversion='Ubuntu 11.4.0-1ubuntu1~22.04' --with-bugurl=file:///usr/share/doc/gcc-11/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-11 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-11-XeT9lY/gcc-11-11.4.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-11-XeT9lY/gcc-11-11.4.0/debian/tmp-gcn/usr --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-serialization=2
> Thread model: posix
> Supported LTO compression algorithms: zlib zstd
> gcc version 11.4.0 (Ubuntu 11.4.0-1ubuntu1~22.04)
> COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/11/:/usr/lib/gcc/x86_64-linux-gnu/11/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/11/:/usr/lib/gcc/x86_64-linux-gnu/
> LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/11/:/usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/11/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/11/../../../:/lib/:/usr/lib/
> COLLECT_GCC_OPTIONS='-v' '-o' 'poole' '-ggdb' '-Wall' '-Wextra' '-mtune=generic' '-march=x86-64' '-dumpdir' 'poole.'
> /usr/lib/gcc/x86_64-linux-gnu/11/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/11/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/11/lto-wrapper -plugin-opt=-fresolution=/tmp/ccYawT3g.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro -o poole /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/11/crtbeginS.o -L/usr/lib/gcc/x86_64-linux-gnu/11 -L/usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/11/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/11/../../.. poole.o utils.o request_queue.o -lpthread -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/x86_64-linux-gnu/11/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/crtn.o
> /usr/bin/ld: request_queue.o: in function `SEM_constructor_with_name':
> /home/guille/git-repos/HAL9000System/semaphore_v2.h:78: multiple definition of `SEM_constructor_with_name'; poole.o:/home/guille/git-repos/HAL9000System/semaphore_v2.h:78: first defined here
> /usr/bin/ld: request_queue.o: in function `SEM_constructor':
> /home/guille/git-repos/HAL9000System/semaphore_v2.h:100: multiple definition of `SEM_constructor'; poole.o:/home/guille/git-repos/HAL9000System/semaphore_v2.h:100: first defined here
> /usr/bin/ld: request_queue.o: in function `SEM_init':
> /home/guille/git-repos/HAL9000System/semaphore_v2.h:115: multiple definition of `SEM_init'; poole.o:/home/guille/git-repos/HAL9000System/semaphore_v2.h:115: first defined here
> /usr/bin/ld: request_queue.o: in function `SEM_destructor':
> /home/guille/git-repos/HAL9000System/semaphore_v2.h:127: multiple definition of `SEM_destructor'; poole.o:/home/guille/git-repos/HAL9000System/semaphore_v2.h:127: first defined here
> /usr/bin/ld: request_queue.o: in function `SEM_wait':
> /home/guille/git-repos/HAL9000System/semaphore_v2.h:141: multiple definition of `SEM_wait'; poole.o:/home/guille/git-repos/HAL9000System/semaphore_v2.h:141: first defined here
> /usr/bin/ld: request_queue.o: in function `SEM_signal':
> /home/guille/git-repos/HAL9000System/semaphore_v2.h:159: multiple definition of `SEM_signal'; poole.o:/home/guille/git-repos/HAL9000System/semaphore_v2.h:159: first defined here
> /usr/bin/ld: poole.o: in function `worker':
> /home/guille/git-repos/HAL9000System/poole.c:43: undefined reference to `fmin'
> collect2: error: ld returned 1 exit status
> make: *** [makefile:16: poole] Error 1
The make file is the following:
> all: bowman Poole discovery
>
> bowman: bowman.o utils.o
> gcc bowman.o utils.o -o bowman -ggdb -Wall -Wextra
>
> bowman.o: bowman.c utils.h
> gcc -c bowman.c -ggdb -Wall -Wextra
>
> discovery: discovery.o utils.o
> gcc discovery.o utils.o -o discovery -ggdb -Wall -Wextra
>
> discovery.o: discovery.c utils.h
> gcc -c discovery.c -ggdb -Wall -Wextra
>
> poole: poole.o utils.o request_queue.o
> gcc -v poole.o utils.o request_queue.o -o poole -ggdb -Wall -Wextra -lpthread
>
> poole.o: poole.c utils.h request_queue.h
> gcc -c poole.c -ggdb -Wall -Wextra -lpthread
>
> request_queue.o: request_queue.c request_queue.h
> gcc -c request_queue.c -ggdb -Wall -Wextra -lpthread
>
> utils.o: utils.c utils.h
> gcc -c utils.c -ggdb -Wall -Wextra
>
> .PHONY: clean
> clean:
> rm *.o
> rm bowman
> rm poole
> rm discovery
These are the headers included in every file in the project:
utils.h
:
#ifndef _UTILS_H
#define _UTILS_H
#define _GNU_SOURCE
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include <limits.h>
...
#endif
Poole.c
:
#define _GNU_SOURCE
#include <stdio.h>
#include <math.h>
#include <sys/poll.h>
#include "utils.h"
#include "request_queue.h"
...
utils.c
:
#include "utils.h"
...
request_queue.h
:
#ifndef _REQUEST_QUEUE
#define _REQUEST_QUEUE
#include <pthread.h>
#include <stdbool.h>
#include "semaphore_v2.h"
...
#endif
request_queue.c
:
#include "request_queue.h"
...
semaphore_v2.h
:
#ifndef _MOD_SEMAPHORE_H_
#define _MOD_SEMAPHORE_H_
/////////////////////////////////////////////////////////////////////////////
/**
* @file semaphore.h
* @author Jorge Solanas
* @date October 5, 2011
* @brief Library to facilitate the use of semaphores
*
* (c) Copyright La Salle BCN, 2011.
* All rights reserved. Copying or other reproduction of this program except
* for archival purposes is prohibited without written consent of
* La Salle BCN.
*/
//////////////////////////////////////////////////////////////////////////////
//#define __USE_SVID
#define __USE_XOPEN
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <assert.h>
#include <stdlib.h>
/**
* Union which must be explicitly declared by the application.
* It is the fourth argument of the semctl function, and it is
* optional, depending upon the operation requested.
*/
/*union semun
{
int val;
struct semid_ds * buf;
unsigned short * array;
};*/
/**
* Struct used to indicate to a semaphore which operation is
* going to be applied (number of the semaphore, operation and
* flags).
*/
typedef struct
{
unsigned short int sem_num;
short int sem_op;
short int sem_flg;
} sembuf;
/**
* Struct with all the info about a semaphore. In this case,
* only the id is specified.
*/
typedef struct
{
int shmid;
} semaphore;
/**
* This file provides a simple but useful abstraction for
* controlling acces by multiple processes to a common resource.
*/
//////////////////////////////////////////////////////////////////////////////
// V2 SEMAPHORE //
/////////////////////////////////////////////////////////////////////////////
/**
* Method which creates a semaphore which a specific identifier/name.
* Very useful for the session S8 ;)
* @param sem The var where semaphore will be created
* @param name Semaphore name. If there isn't semaphore with this name, it is created.
If it exists, you get the memory region
* @return int The result of the operation executed
*/
int SEM_constructor_with_name(semaphore * sem, key_t key) {
// IPC_CREAT: if this is specified, and a semaphore with the given key does not exist, it is created, otherwise the call returns with -1, setting the appropriate errno value.
sem->shmid = semget(key, 1, IPC_CREAT | 0644);
if (sem->shmid < 0) return sem->shmid;
return 0;
}
//////////////////////////////////////////////////////////////////////////////
// V1 SEMAPHORE //
/////////////////////////////////////////////////////////////////////////////
/**
* Method which creates a semaphore
* @param sem The var where semaphore will be created
* @return int The result of the operation executed
*/
int SEM_constructor (semaphore * sem)
{
assert (sem != NULL);
sem->shmid = semget (IPC_PRIVATE, 1, IPC_CREAT | 0600);
if (sem->shmid < 0) return sem->shmid;
return 0;
}
/**
* Method which initializes a semaphore
* @param sem The semaphore to initialize
* @param v The value to which the semaphores will be
* initialized
* @return int The result of the operation executed
*/
int SEM_init (const semaphore * sem, const int v)
{
unsigned short _v[1] = {v};
assert (sem != NULL);
return semctl (sem->shmid, 0, SETALL, _v);
}
/**
* Method to destroy a semaphore
* @param sem The semaphore to destroy
* @return int The result of the operation executed
*/
int SEM_destructor (const semaphore * sem)
{
assert (sem != NULL);
return semctl (sem->shmid, 0, IPC_RMID, NULL);
}
/**
* Method to apply a wait operation, in order to warn that a
* process is going to use a common resource. The semaphore
* counter will be decreased. If counter has the value zero, the
* process will be added to the semaphore's queue
* @param sem The semaphore where wait operation will be applied
* @return int The result of the operation executed
*/
int SEM_wait (const semaphore * sem)
{
struct sembuf o = {0, -1, SEM_UNDO};
assert (sem != NULL);
return semop(sem->shmid, &o, 1);
}
/**
* Method to apply a signal operation, in order to warn that a
* process has released a common resource. The semaphore counter
* will be increased. If counter had the value zero and there
* are processes in the queue, the top one has the access to the
* common resource granted.
* @param sem The semaphore where signal operation will be
* applied
* @return int The result of the operation executed
*/
int SEM_signal (const semaphore * sem)
{
struct sembuf o = {0, 1, SEM_UNDO};
assert (sem != NULL);
return semop(sem->shmid, &o, 1);
}
#endif /* _MOD_SEMAPHORE_H_ */
The file sempaphore_v2.h
contains definitions of functions that are not marked static inline
(or, at least, static
). That means the file can only be included in one source file in any given program. Otherwise, you get multiple-definition errors like you're seeing.
You say that you don't want to modify semaphore_v2.h
since it was given to you to use (and it appears to be dated 2011, so I can sympathize). As noted in the first paragraph, that means you must write your own code such that only one source file (let's call it semlib.c
) includes semaphore_v2.h
. It defines a series of functions that use the code from semaphore_v2.h
. It has an associated header (semlib.h
) that defines any types you need to use, and declares the functions you plan to use, so that none of the rest of your code needs to include semaphore_v2.h
(and semlib.h
, in particular, will not include semaphore_v2.h
). You can then compile semlib.c
and link it with the rest of your program, which will be revised to use the facilities declared by semlib.h
.
Thanks, that was the problem, although I don't understand it. Why did that happen here but not in my other header files, should I define those also as static?
Presumably, you only declare functions in other headers (e.g. request_queue.h
) and define the functions in a source file (e.g. request_queue.c
). That's the normal way of proceeding — declarations in headers, definitions in source files. The file semaphore_v2.h
violates this rule of thumb and the problems you're seeing are a consequence of it violating that rule.
If you want to include function definitions in a header, then you have to ensure you won't get multiple-definition errors. Either that header is included by just one source file — as proposed in the second paragraph of my answer — or you have to mark the functions static
.
Marking them static
means that each object file created that includes the header will have its own copy of the functions defined in the header. You will need to use all the functions in the header in every source file that includes it to avoid warnings about unused function definitions. Or you can mark the functions static inline
; that still means that each object file will contain a copy of the functions, but only the ones that the source file uses.
Those are pretty much your only options. Both the options using static
(with or without inline
) involve modifying the header. Since you don't want to do that, you have to create the wrapper module (semlib.c
, semlib.h
) to get around the manifest deficiencies in the semaphore_v2.h
header.
In many ways, the best solution would be to rewrite semaphore_v2.h
as two files — semaphore_v2.c
, which contains the function definitions, and a revised semaphore_v2.h
, which only declares the functions and does not define them. That may even be the better option — even though it goes against your desire not to change the external (flawed) header. And the header, as shown, is definitely defective, precisely because it causes the problems you've run into.