Odd duplicate symbol error in C - c

Ok so i have a project, and i have some helper functions which need to be shared in various other files. call it Helper.c /.h , with the corresponding compilation flag to avoid multiple inclusion (#ifndef SymbolName #define Symbolname blah blahblah #endif). Every file has its header file in the following way:
#include ....
#include ....
#ifndef __FILENAME_H__
#define __FILENAME_H__ //in each file(FILENAME is replaced for the current file's name)
declarations of functions, types, etc.
#endif
I have a compare function, called dummyCompare (templates, so when creating a variable of this ADT, you need to supply your own function pointer for it to work, so for some cases i don't need a specific function, just a generic one, so that is what dummyCompare is.
The error i get when compiling is:
gcc ./Helper.c ./LinkedList.c ./ABB.c ./AVL.c -Wall -lm -D DEBUG -g
duplicate symbol _dummyCompare in:
/var/folders/f2/nghjrbz915vbhjw_1gbb65sm0000gn/T//cc75R4sQ.o
/var/folders/f2/nghjrbz915vbhjw_1gbb65sm0000gn/T//cc8jQwyE.o
ld: 1 duplicate symbol for architecture x86_64
collect2: ld returned 1 exit status
List is used for a non-recursive solution for tree operations in ABB(ABB = BST in spanish)/AVL. Now using Sublime Text 2, i get the following search results for "dummyCompare"
Searching 8 files for "dummycompare"
/dir/ABB.c:
81 if (abb != NULL) {
82 if (ABB_getRoot(*abb) != NULL){
83: list = LL_newList(dummyCompare);
84 LL_insert(list, 1, ABB_getRoot(*abb));
85
/dir/AVL.c:
67 if (avl != NULL) {
68 if (AVL_getRoot(*avl) != NULL){
69: list = LL_newList(dummyCompare);
70 LL_insert(list, 1, AVL_getRoot(*avl));
71
/dir/Helper.c:
2
3 /****************************************************************************
4: * dummyCompare *
5 *****************************************************************************
6 * Retorna si 2 dirrecciones son iguales, necesario para el funcionamiento *
7 * de la lista *
8 ****************************************************************************/
9: int dummyCompare(void * a, void * b)
10 {
11 if (a == b)
/dir/Helper.h:
4
5 int getMax(int a, int b);
6: int dummyCompare(void * a, void * b);
7
8 #endif
5 matches across 4 files
Thing is i can't seem to understand what is wrong, and why am I getting this error. Checked a lot of other question, and only answer i found was ("use #ifndef ... "), which I'm using

Related

using Makefiles in c, declaring variables multiple definitions

i am using makefiles in c, i have three files and each of the three have all the declarations of each variable. so it looks like this when i compile.
/usr/bin/ld: comp_disc.o:(.bss+0x8): multiple definition of `Cost_of_purchase'; main.o:(.bss+0x8): first defined here
/usr/bin/ld: comp_disc.o:(.bss+0x10): multiple definition of `DiscTot'; main.o:(.bss+0x10): first defined here
/usr/bin/ld: comp_disc.o:(.bss+0x18): multiple definition of `Sales_tax'; main.o:(.bss+0x18): first defined here
/usr/bin/ld: comp_disc.o:(.bss+0x20): multiple definition of `Total_price'; main.o:(.bss+0x20): first defined here
/usr/bin/ld: comp_disc.o:(.bss+0x28): multiple definition of `military'; main.o:(.bss+0x28): first defined here
but when i only keep those declarations on main.c i get this.
comp_disc.c:10:12: error: ‘Cost_of_purchase’ undeclared (first use in this function)
10 | if(Cost_of_purchase > 150) {
| ^~~~~~~~~~~~~~~~
comp_disc.c:11:13: error: ‘Mdisc’ undeclared (first use in this function)
11 | Mdisc = .15 * Cost_of_purchase;
so I'm wondering what i need to do so that my variables are declared correctly using make
here is my makefile
# target : dependencies
2 cwork7 : main.o comp_disc.o print_res.o
3 gcc main.o comp_disc.o print_res.o -Wall -o cwork7
4
5 main.o : main.c
6 gcc -c main.c -Wall
7
8 comp_disc : comp_disc.c
9 gcc -c comp_disc.c -Wall
10
11 print_res.o : print_res.c
12 gcc -c print_res.c -Wall
my main.c
5 #include <stdio.h>
6 //functions prototypes
7 void compute_discount(void);
8 int print_results(void);
9
10
11 //defined Gloabal var
12 double Mdisc;
13 double Cost_of_purchase;
14 double DiscTot;
15 double Sales_tax;
16 double Total_price;
17 char military;
18
19 int main (void) {
20 //declare variables
21
22 //Cost of purchase
23 printf("Cost of purchase?\t\t$");
24 scanf ("%lf",&Cost_of_purchase);
25
26 //Military?
27 printf("In military (y or n)?\t\t");
28 scanf(" %c" ,&military);
29
30 //calling for functions
31 compute_discount();
32 print_results();
33
34 }
35
36
my print_res.c
1 #include <stdio.h>
2
3 //function to print results
4 int print_results(void){
5
6 //if input is y Y then use below, this is not dependant on if military only if the letter is accepted
7 switch(military){
8 case 'y':
9 case 'Y':
10 printf("Military discount (15%%): \t$%.2f\n", Mdisc);
11 printf("Discounted total: \t\t$%.2f\n", DiscTot);
12 printf("Sales tax (5%%): \t\t$%.2f\n", Sales_tax);
13 printf("Total: \t\t\t\t$%.2f\n", Total_price);
14 break;
15 //less information is given when n or N is used
16 case 'n':
17 case 'N':
18 printf("Sales tax (5%%): \t\t$%.2f\n", Sales_tax);
19 printf("Total: \t\t\t\t$%.2f\n", Total_price);
20 break;
21 }
22 return(0);
23 }
and my comp_disc.c
1 #include <stdio.h>
2
3 //function to compute discount
4 void compute_discount(void){
5
6 //compute military discount
7 switch(military){
8 case 'y':
9 case 'Y':
10 if(Cost_of_purchase > 150) {
11 Mdisc = .15 * Cost_of_purchase;
12 } else if (Cost_of_purchase < 150) {
13 Mdisc = .10 * Cost_of_purchase;
14 }
15 break;
16 case 'n':
17 case 'N':
18 Mdisc = 0;
19 break;
20 default:
21 printf("Error: bad input\n");
22 }
23
24 //cost minus military discount
25 DiscTot = Cost_of_purchase - Mdisc;
26 //sales tax
27 Sales_tax = .05 * DiscTot;
28 //Total Calculated
29 Total_price = DiscTot + Sales_tax;
30
31 }
Please let me know what you think is the issue.
This has nothing to do with the Makefile.
If you define the variables in all source file you get exactly what the linker says, multiple definitions of the same name. And if you drop them from the file you obviously get a compile error as you are using variables the compiler does not know about.
The simple solution is to keep the variables in main as-is, but to define them as extern in all other files, like extern double Cost_of_purchase; That tells the compiler the variable exists, but is already defined elsewhere, which solves the problem.
However, just don't use global variables. Pass your data to the functions.
struct acc_data {
double Mdisc;
double Cost_of_purchase;
double DiscTot;
double Sales_tax;
double Total_price;
char military;
}
int main(void)
{
struct acc_data acc = { 0 };
// init code skipped
compute_discount(&acc);
print_results(&acc);
}
void compute_discount(struct acc_data *acc)
{
//same as before but prefix variables with acc->
// example:
acc->Total_price = 5000.0;
}
That gets rid of your original problem and improves your code somewhat.
Put the definition of the struct in a header file you include in all C files that use it.

Using fdlibm library in C

I am trying to use the fdlibm library in C to compute sin of a large number. I used the code from this link: http://www.netlib.org/fdlibm/ and downloaded the folder "s_sin.c plus dependencies". When I run the c code in that folder "s_sin.c", I get the following error:
Undefined symbols for architecture x86_64:
"___ieee754_rem_pio2", referenced from:
_sin in s_sin-a92222.o
"___kernel_cos", referenced from:
_sin in s_sin-a92222.o
"___kernel_sin", referenced from:
_sin in s_sin-a92222.o
"_main", referenced from:
implicit entry/start for main executable
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Any ideas how to fix this error?
Here is the code that I mentioned above:
/* #(#)s_sin.c 1.3 95/01/18 */
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunSoft, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
/* sin(x)
* Return sine function of x.
*
* kernel function:
* __kernel_sin ... sine function on [-pi/4,pi/4]
* __kernel_cos ... cose function on [-pi/4,pi/4]
* __ieee754_rem_pio2 ... argument reduction routine
*
* Method.
* Let S,C and T denote the sin, cos and tan respectively on
* [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
* in [-pi/4 , +pi/4], and let n = k mod 4.
* We have
*
* n sin(x) cos(x) tan(x)
* ----------------------------------------------------------
* 0 S C T
* 1 C -S -1/T
* 2 -S -C T
* 3 -C S -1/T
* ----------------------------------------------------------
*
* Special cases:
* Let trig be any of sin, cos, or tan.
* trig(+-INF) is NaN, with signals;
* trig(NaN) is that NaN;
*
* Accuracy:
* TRIG(x) returns trig(x) nearly rounded
*/
#include "fdlibm.h"
#ifdef __STDC__
double sin(double x)
#else
double sin(x)
double x;
#endif
{
double y[2],z=0.0;
int n, ix;
/* High word of x. */
ix = __HI(x);
/* |x| ~< pi/4 */
ix &= 0x7fffffff;
if(ix <= 0x3fe921fb) return __kernel_sin(x,z,0);
/* sin(Inf or NaN) is NaN */
else if (ix>=0x7ff00000) return x-x;
/* argument reduction needed */
else {
n = __ieee754_rem_pio2(x,y);
switch(n&3) {
case 0: return __kernel_sin(y[0],y[1],1);
case 1: return __kernel_cos(y[0],y[1]);
case 2: return -__kernel_sin(y[0],y[1],1);
default:
return -__kernel_cos(y[0],y[1]);
}
}
}
The problem is you need to build libm.a from the fdlibm files. If you look at readme file it explains:
CONFIGURE
To build FDLIBM, edit the supplied Makefile or create
a local Makefile by running "sh configure"
using the supplied configure script contributed by Nelson Beebe
(note: after downloading all the files and makefile, you can simply type make and it will build libm.a)
This will create libm.a (which you can link with instead of the normal math library). After you build the library, you need only #include "fdlibm.h" in your source file and compile similar to:
gcc -Wall -Wextra -pedantic -std=c11 -Ofast -L./ -o test_s_sin test_s_sin.c -lm
This will compile your code (named test_s_sin.c above) to executable.
The reason you cannot simply build s_sin.c with gcc is if you look in s_sin.c, you will find it depends on a number of additional externally defined functions from fdlibm (which in turn depend on other source file in the library). For example in s_sin.c you have:
/* High word of x. */
ix = __HI(x);
/* |x| ~< pi/4 */
ix &= 0x7fffffff;
if(ix <= 0x3fe921fb) return __kernel_sin(x,z,0);
/* sin(Inf or NaN) is NaN */
else if (ix>=0x7ff00000) return x-x;
/* argument reduction needed */
else {
n = __ieee754_rem_pio2(x,y);
switch(n&3) {
case 0: return __kernel_sin(y[0],y[1],1);
case 1: return __kernel_cos(y[0],y[1]);
case 2: return -__kernel_sin(y[0],y[1],1);
default:
return -__kernel_cos(y[0],y[1]);
}
Where you have the functions or macros __HI(), __kernel_sin(), __ieee754_rem_pio2(), etc.. all required by s_sin.c. These are provided by the other sources in fdlibm, but are all meant to work together as a library rather than single source files you can cherry-pick from.

Implementing Dynamic Memory Management Functions

I tryed to implement dynamic memory managemet functions and succeed. However when I try to implement another function that prints some information about memory with the exact same way, I got segmentation fault. I am using Ubuntu, gcc.
Here is my related code:
In mm_alloc.c: (Other functions malloc, free etc. are also here)
#include "mm_alloc.h"
#include "stdlib.h"
#include "stdio.h"
#include "unistd.h"
#include "string.h"
void mm_print_mem() {
printf( "\nstart_addr\tsize\tfree\tprev\tnext\n");
printf("=============================\n");
printf("HEAD OF LL %p\n", metadata);
METADATA *currentPtr = metadata;
int i = 0;
while (currentPtr!= NULL && i <= 10) {
printf("%p\t%d\t%d\t%p\t%p\n", currentPtr, (int)currentPtr-
>size, currentPtr->free,currentPtr->prev,currentPtr->next);
if (currentPtr->next == NULL) break;
currentPtr = currentPtr->next;
i++;
}
return;
}
mm_alloc.h:
#pragma once
#include <stdlib.h>
typedef struct METADATA{
struct METADATA *next;
struct METADATA *prev;
int free;
size_t size;
}METADATA;
METADATA *metadata;
void *mm_malloc(size_t size);
void *mm_realloc(void *ptr, size_t size);
void mm_free(void *ptr);
void mm_print_mem();
And the test function. Here, I got segmentation fault when I call mm_print_mem function, others work well.
int main() {
load_alloc_functions();
int *dizi = (int *)mm_malloc(5 * sizeof(int));
dizi[4] = 5;
dizi[2] = 10;
printf("%d - %d\n", dizi[4], dizi[2]);
mm_print_mem();
return 0;
}
I use these commands on Ubuntu in order to link files and run the test file.
gcc -c -Wall -Werror -fpic mm_alloc.c
gcc -shared -o libfoo.so 14011085.so
gcc mm_test.c -o try -ldl
./try
Notice that even the inside of mm_print_mem was empty, it gives segmentation fault as well. Where am I doing wrong?
You have at least a problem in the declaration of the global variable metadata. It is declared as METADATA *metadata; in an included file. So it has correctly external linkage, but is defined in every translation unit, when one single definition should exist in a full program. Not doing so is explicitely undefined behaviour, with no diagnostic required.
There are different ways to fix that problem:
declare it extern in the include file
extern METADATA *metadata;
and define it in only one translation unit without the extern specifier:
#include "mm_alloc.h" // extern declaration
...
METADATA * metadata; // single definition in whole program
put all the library functions in one single translation unit (if it makes sense), define metadata in that file and remove any reference to it from the mm_alloc.h file. After all, it is private data for the library...
remove the reference to metadata from the mm_alloc.h include file which should only declare the external interface for the library, define it in one single file of the library (at file level without the extern specifier) and declare it in all other files from the library as extern METADATA *metadata;
Without seeing the source for the other functions I cannot say whether there are other problems...
You make things a bit difficult by not providing a A Minimal, Complete, and Verifiable example, but a short example will help. Without seeing your load and alloc functions, you leave us guessing a bit at exactly where your problem is located or the extent of you problems.
That said a short example illustrating your mm_print_mem(); function should at least get that part straightened out. (note: the example uses a cirular linked list where the last node points to the first and first->prev points to the last. You can adjust the test and assignments for metadata->prev and last->next if you want NULL at both ends)
While you can use #pragma once, you will find greater portability just using traditional header-guards to prevent multiple includes, e.g. #ifndef HEADERNAME, then #define it, e.g.
#ifndef __mm_alloc_h__
#define __mm_alloc_h__ 1
#include <stdlib.h>
typedef struct METADATA {
struct METADATA *next;
struct METADATA *prev;
int free;
size_t size;
} METADATA;
METADATA *metadata;
// void *mm_malloc(size_t size);
// void *mm_realloc(void *ptr, size_t size);
// void mm_free(void *ptr);
void mm_print_mem();
#endif
Your mm_alloc.c is fine, but your loop control was a bit strange with the magic number 10 included as a condition. With the example list, you simply iterate and increment nodes until currentPtr->next (e.g. currentPtr after assignment) is equal to metadata (completing the circle)
#include "mm_alloc.h"
#include <stdio.h>
void mm_print_mem() {
METADATA *currentPtr = metadata;
printf ("\nstart_addr\tsize\tfree\tprev\t\tnext\n"
"=========================================================\n"
"HEAD OF LL %p\n", metadata);
for (;;) {
printf ("%p\t%d\t%d\t%p\t%p\n", currentPtr, (int)currentPtr->size,
currentPtr->free,currentPtr->prev,currentPtr->next);
currentPtr = currentPtr->next;
if (currentPtr == metadata)
break;
}
}
I wrote a simple test program that allocates and fills 20 nodes for you showing the independent handling of the 1st and remaining nodes, e.g,
#include "mm_alloc.h"
#include <stdio.h>
#define MAX 20
int main (void) {
int i;
for (i = 0; i < MAX; i++) {
METADATA *node = malloc (sizeof *node);
if (!node) {
perror ("malloc node");
return 1;
}
node->next = node->prev = NULL;
node->free = MAX - i - 1;
node->size = i;
if (!metadata) { /* 1st node is self-referencing */
node->prev = node; /* in circular linked-list */
node->next = node;
metadata = node;
}
else { /* add rest at end as metadata->prev */
node->prev = metadata->prev;
node->next = metadata;
metadata->prev->next = node;
metadata->prev = node;
}
}
mm_print_mem();
return 0;
}
(note: you should free the node when you are done with them)
Compile Shared Object Library & Test Program
$ gcc -Wall -Werror -fPIC -o mm_alloc.o -c mm_alloc.c
$ gcc -shared -o libmm_alloc.so mm_alloc.o
When compiling the test program, make sure your program can find your shared library. using the linker option -rpath is a good way to specify the location for a custom library if not in the standard library search path locations. (just note it must be in the same place on any system you copy it too)
(line-continuation are used below to allow the compile string to fit)
$ gcc -L"/path/to/your/lib/dir" \
-Wl,-rpath="/path/to/your/lib/dir" \
-Wall -o mm_alloc_tst mm_alloc_tst.c -lmm_alloc
Example Use/Output
$ ./mm_alloc_tst
start_addr size free prev next
=========================================================
HEAD OF LL 0x208d010
0x208d010 0 19 0x208d3a0 0x208d040
0x208d040 1 18 0x208d010 0x208d070
0x208d070 2 17 0x208d040 0x208d0a0
0x208d0a0 3 16 0x208d070 0x208d0d0
0x208d0d0 4 15 0x208d0a0 0x208d100
0x208d100 5 14 0x208d0d0 0x208d130
0x208d130 6 13 0x208d100 0x208d160
0x208d160 7 12 0x208d130 0x208d190
0x208d190 8 11 0x208d160 0x208d1c0
0x208d1c0 9 10 0x208d190 0x208d1f0
0x208d1f0 10 9 0x208d1c0 0x208d220
0x208d220 11 8 0x208d1f0 0x208d250
0x208d250 12 7 0x208d220 0x208d280
0x208d280 13 6 0x208d250 0x208d2b0
0x208d2b0 14 5 0x208d280 0x208d2e0
0x208d2e0 15 4 0x208d2b0 0x208d310
0x208d310 16 3 0x208d2e0 0x208d340
0x208d340 17 2 0x208d310 0x208d370
0x208d370 18 1 0x208d340 0x208d3a0
0x208d3a0 19 0 0x208d370 0x208d010
Look things over and let me know if you have further questions.

C easy code with filling array

I'm trying to fill an array with a file called data.txt. I don't know what's wrong with code. I get segmentation fault: 11 error.
#include <stdio.h>
#include <stdlib.h>
void input(int arr[]){
FILE* f;
int x, i=0;
f= fopen("data.txt","r");
while (arr[i] != EOF){
fscanf(f,"%d",&x);
arr[i] = x;
i++;
}
fclose(f);
}
int main(){
int arr[50];
input(&arr[50]);
printf("%d", arr[0]);
}
You are reading the number into x (which you are copying into arr[i]) and then comparing arr[i+1] to EOF. That is not how it has to be done.
Try this
while (fscanf(f, "%d", &arr[i]) == 1)
i++;
But this would violate so many safety constraints. Better also bound check and break early if i is greater than some limit, but that limit should be passed to the function.
Another error is with how you are passing arguments to input. Pass input(arr) instead of input(&arr[50]). If you want to use & use input(&arr[0]).
This would be more nearly my version of your code:
#include <stdio.h>
#include <stdlib.h>
static int input(int size, int arr[])
{
const char file[] = "data.txt";
FILE *f = fopen(file, "r");
if (f == NULL)
{
fprintf(stderr, "Failed to open file '%s' for reading\n", file);
exit(EXIT_FAILURE);
}
int i;
for (i = 0; i < size && fscanf(f, "%d", &arr[i]) == 1; i++)
;
fclose(f);
return i;
}
int main(void)
{
int arr[50];
int num = input(50, arr);
for (int i = 0; i < num; i++)
printf("%d: %d\n", i, arr[i]);
return 0;
}
The use of static before the function is necessary to quell -Wmissing-prototypes. The main() function tells the input() function how many elements are in the array so the input() function can avoid overflowing the buffer (a stack overflow, no less). The input() function tells the main() function how many values it read, so the main() function doesn't go accessing data that was not initialized. The crucial function calls are error checked — fopen() and fscanf().
The code compiles cleanly on a Mac running macOS Sierra 10.12.4 using GCC 6.3.0 and the command line below (the source file was rf19.c):
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
> -Wstrict-prototypes -Wold-style-definition rf19.c -o rf19
$
I generated a data file with 23 random integers between 10 and 99 in it, and the output was:
$ ./rf19
0: 48
1: 33
2: 77
3: 42
4: 78
5: 51
6: 85
7: 56
8: 55
9: 56
10: 16
11: 38
12: 39
13: 52
14: 34
15: 63
16: 20
17: 23
18: 23
19: 19
20: 39
21: 44
22: 71
$
That's not dreadfully informative, but better than nothing.
The code has deficiencies still, which I don't plan to fix — some more serious than others. For example, the file name is fixed — that's a no-no. The code in the input() function exits on error; that isn't necessarily OK. It produces an error message on standard error — that's better than standard output, but wouldn't be a good idea in a GUI application. The output wastes a lot of horizontal space; with the data shown, you could get 10 values per output line (that would use about 70 characters per line), but the printing for that is more intricate, so I didn't show it. The code treats EOF and a word or punctuation character in the data the same; that might or might not matter, depending on your application. The input simply stops after the 50th entry; maybe you need to know whether there were more entries available to read. I'd probably process the command line arguments as file names, or process standard input if no files were specified — the Unix 'filter command' idiom. I'd probably do something more exciting than just print the first fifty values. I'd probably put the file reading code in a separate function from the file open/close code.

Issues with make and #include

Somewhere between my headers and my Makefile I'm not doing the dependencies correctly, and it's not compiling. This really only has anything to do with the first few lines from each code, but I posted all the code for reference
I'm trying to split up a who clone into 3 parts. Here is the original for reference. The exercise is to make it with utmp, so you also need utmplib
So I've split it up into 3 files, the first one being show.h
#include <stdio.h>
#include <sys/types.h>
#include <utmp.h>
#include <fcntl.h>
#include <time.h>
#include <stdlib.h>
#define SHOWHOST
void show_info(struct utmp *);
void showtime(time_t);
then I have show.c
/*
* * show info()
* * displays the contents of the utmp struct
* * in human readable form
* * * displays nothing if record has no user name
* */
void show_info( struct utmp *utbufp )
{
if ( utbufp->ut_type != USER_PROCESS )
return;
printf("%-8.8s", utbufp->ut_name); /* the logname */
printf(" "); /* a space */
printf("%-8.8s", utbufp->ut_line); /* the tty */
printf(" "); /* a space */
showtime( utbufp->ut_time ); /* display time */
#ifdef SHOWHOST
if ( utbufp->ut_host[0] != '\0' )
printf(" (%s)", utbufp->ut_host); /* the host */
#endif
printf("\n"); /* newline */
}
void showtime( time_t timeval )
/*
* * displays time in a format fit for human consumption
* * uses ctime to build a string then picks parts out of it
* * Note: %12.12s prints a string 12 chars wide and LIMITS
* * it to 12chars.
* */
{
char *ctime(); /* convert long to ascii */
char *cp; /* to hold address of time */
cp = ctime( &timeval ); /* convert time to string */
/* string looks like */
/* Mon Feb 4 00:46:40 EST 1991 */
/* 0123456789012345. */
printf("%12.12s", cp+4 ); /* pick 12 chars from pos 4 */
}
and finally, `who3.c'
/* who3.c - who with buffered reads
* - surpresses empty records
* - formats time nicely
* - buffers input (using utmplib)
*/
#include "show.h"
int main()
{
struct utmp *utbufp, /* holds pointer to next rec */
*utmp_next(); /* returns pointer to next */
if ( utmp_open( UTMP_FILE ) == -1 ){
perror(UTMP_FILE);
exit(1);
}
while ( ( utbufp = utmp_next() ) != ((struct utmp *) NULL) )
show_info( utbufp );
utmp_close( );
return 0;
}
So I created my Makefile:
who3:who3.o utmplib.o
gcc -o who who3.o utmplib.o
who3.o:who3.c show.c
gcc -c who3.c show.o
show.o:show.c
gcc -c show.c show.h
utmplib.o:utmplib.c
gcc -c utmplib.c
clean:
rm -f *.o
Unfortunately there's an error when I do make:
gcc -o who who3.o utmplib.o
who3.o: In function `main':
who3.c:(.text+0x38): undefined reference to `show_info'
collect2: error: ld returned 1 exit status
make: *** [who3] Error 1
As I said earlier, I haven't done my dependencies correctly, and I'm not sure what I did wrong. How do I do my dependencies correctly?
It looks like you are missing show.o from the dependencies and from the list of object files of the command for building who3 in your makefile.
Also, the command for who3.o looks wrong. You are compiling only -c, but you are passing an object file as input (show.o). You should remove show.o from the rule and show.c doesn't belong on the list of dependencies of who3.o either.
Also, the command for show.o looks wrong. You shouldn't be passing header files (show.h) to the compiler; they only need to be referenced as #include in the source files.
Also, you are inconsistent about what your default is actually called. You say it is who3 in the rule (who3: ...) but the command will actually build a task called who (gcc -o who ...).

Resources