undefined reference to `stack_init' - c

test.c
#include <stdio.h>
#include <stdlib.h>
#include "dslib.h"
//#include "stack.c"
int main()
{
stack myStack;
char buffer[1024];
stack_init(&myStack, 6);
int i;
for(i = 0; i < myStack.max; i++){
stack_push(&myStack, (i+1)*2);
}
printf("Hello\n");
return 0;
stack.c
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "dslib.h"
//#define stack_init main
void stack_init(stack *s, int capacity)
{
// struct stack_t *s = (struct stack_t*)malloc(sizeof(struct stack_t));
s->max = capacity;
s->count = -1;
s->data = (int*)malloc(capacity * sizeof(int));
//return s;
}
int stack_size(stack *s)
{
return s->count;
}
int stack_pop(stack *s)
{
if(s->count == 0){
return -1;
}
s->count--;
int pop = s->data[s->count];
s->data[s->count] = 0;
return pop;
}
void stack_push(stack *s, int e)
{
if(s->count != s->max){
s->data[s->count] = e;
s->count++;
}
}
void stack_deallocate(stack *s)
{
free(s->data);
}
dslib.h
#ifndef DSLIB_H
#define DSLIB_H
#include <stdio.h>
#include <stdlib.h>
typedef struct stack
{
int count; // the number of integer values currently stored in the stack
int *data; // this pointer will be initialized inside stack_init(). Also, the actual size of
//the allocated memory will be determined by “capacity’ value that is given as one of the
//parameters to stack_init()
int max; // the total number of integer values that can be stored in this stack
}stack;
void stack_init(stack* s, int capacity);
int stack_size(stack *s);
int stack_pop(stack *s);
void stack_push(stack *s, int e);
void stack_deallocate(stack *s);
#endif
Makefile
cc=gcc
file: test.o stack.o file.o
gcc -o file test.o stack.o file.o
file.o: file.c
gcc -o file.o file.c
test.o: test.c
gcc -o test.o test.c
stack.o: stack.c
gcc -o stack.o stack.c
When I execute make, it emits this:
gcc -o test.o test.c
/tmp/ccJMitGw.o: In function `main':
test.c:(.text+0x2a): undefined reference to `stack_init'
test.c:(.text+0x53): undefined reference to `stack_push'
collect2: error: ld returned 1 exit status
Makefile:10: recipe for target 'test.o' failed
make: *** [test.o] Error 1

gcc -o test.o test.c
This attempts to compile and link test.c into an executable with the unusual name of test.o. That obviously fails because test.c is not a complete program by itself.
To just compile and assemble a source file into an object file, you need to use the -c option:
gcc -c -o test.o test.c
And the same for the other compilation rules of your makefile.
There is a slight inconsistency in gcc's behavior here: it looks at the extension of the input files to help it decide what to do (.c files get compiled as C, .cpp files are compiled as C++, .s files are only assembled, etc) but it doesn't look at the extension of the output file. You have to use a separate option.

My answer is intended to follow on Nate's. Mine's a bit too complicated to put into a comment.
The default file production rules should work just fine for your Makefile unless on your platform the defaults are different. On mine, this is all I need to make the executable:
file: test.o stack.o
gcc -o file test.o stack.o
You didn't include file.c but the code you posted doesn't depend upon file.c.
It's highly recommended to use pre-defined rules whenever possible and to define new rules where they can be applied more than once. The only time you truly need specific rules is when multiple rules cannot be refactored to a smaller set of rules.
PS I'd never want to create an executable named for something that already exists.

Create a header file for the stack.c file and include it in your main file instead of stack.c
stack.h
#ifndef STACK_H
#define STACK_H
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "dslib.h"
void stack_init (stack * s, int capacity);
int stack_size (stack * s);
int stack_pop (stack * s);
void stack_push (stack * s, int e);
void stack_deallocate (stack * s);
#endif
stack.c
#include "stack.h"
/* code */
test.c
#include "stack.h"
/* code */

Related

How to resolve linker when when using multiple files in Virtual-C? [duplicate]

I have this simple test file:
#include "stack.h"
int main()
{
Stack* stck = init_stack();
return 0;
}
and stack.h is defined as follows:
#ifndef STACK_H
#define STACK_H
#define EMPTY_STACK -1
typedef struct stack
{
char ch;
struct stack* prev;
} Stack;
extern Stack* init_stack();
extern char pop(Stack*);
extern void push(Stack*, char);
#endif
These two files are in the same directory. But when I do gcc .. to build it, I keep getting the error below:
$ ls
stack.c stack.h teststack.c
$ gcc -o testit teststack.c
/tmp/ccdUD3B7.o: In function `main':
teststack.c:(.text+0xe): undefined reference to `init_stack'
collect2: ld returned 1 exit status
Could anyone tell me what I did wrong here?
Thanks,
gcc -o testit teststack.c stack.c
You need to compile both C source files and link the object files; this does it all in one command.

Weird Error when implementing Stack in C

I'm trying to implement stack in C and it got the weird error in my MinGw compiler
gcc -Wall -o stack stack.c
Stack.c
#include "stack.h"
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
Stack *create(int size) {
Stack *result;
result = (Stack *) malloc( sizeof(Stack) * size );
assert(result != NULL);
result -> file = result;
result -> maxAllocate = size;
result -> top = -1;
return result;
}
stack.h
#define MAX_SIZE 1024
typedef struct {
void **file;
int top;
int maxAllocate; // current size of array allocated for stack
} Stack;
Stack *create(int size);
int push(Stack *s, void *x);
void *pop(Stack *s);
int isEmpty(Stack *s);
error
C:\test>gcc -Wall -o stack stack.c
stack.c: In function 'create':
stack.c:26:17: warning: assignment from incompatible pointer type [enabled by de
fault]
c:/mingw/bin/../lib/gcc/mingw32/4.6.2/../../../libmingw32.a(main.o): In function
`main':
C:\MinGW\msys\1.0\src\mingwrt/../mingw/main.c:73: undefined reference to `WinMai
n#16'
collect2: ld returned 1 exit status
With gcc -Wall -o stack stack.c you compile only stack.c (which has o main function in it) but for a functioning application you will also need a main function, as the main entry point: http://en.wikipedia.org/wiki/Entry_point
using gcc with -o option means you want to compile, link and run your program (this command won't run it, but usually that's the reason with such usage). You cannot run a program without an entry point (in this case it's main function).
If you only want to check if your stack.c compiles use gcc -Wall -c stack.c.

Difference between getting function pointers from shared library

The question is how I can get function address from shared library (UNIX/LINUX)?
I had written some testcases in C (see below), compiled and run on Ubuntu 10.04 (amd64) and FreeBSD-8.2 (amd64). I hadn't feel any difference but I want to know more about possible troubles.
Here they are:
Test 1
lib.c
char* f0(void) {
return "Hello, World!";
}
main.c
#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>
void *hlib, *addr;
char* (*foo)(void);
char* s;
int main(int argc, char** argv) {
if ( !(hlib = dlopen("./lib.so", RTLD_LAZY)) )
return 1;
if ( !(addr = foo = dlsym(hlib, "f0")) )
return 2;
s = foo();
printf("%p => %s\n", addr, s);
return 0;
}
Now build it:
gcc -o lib.o -c lib.c -Wall -Werror -O3 -fPIC
gcc -o lib.so -shared -nostartfiles lib.o
gcc -o main.o -c main.c -Wall -Werror -O3
gcc -o prog main.o -ldl
This prints the address of library function f0() and the result of execution.
Test 2
lib.h (define here the standard interface of dynamically linking libraries)
#ifndef __LIB_H__
#define __LIB_H__
typedef struct __syminfo {
char* name; // function name
void* addr; // function address
} syminfo_t;
typedef struct __libinfo {
int num; // number of exported functions
syminfo_t sym[1]; // vector of exported function information
} libinfo_t;
extern int (*__getinfo)(libinfo_t**);
#endif
/* __LIB_H__
*/
lib.c (the library itself)
#include <stdlib.h>
#include <lib.h>
static libinfo_t* li;
char* foo(void);
__attribute__((constructor)) void __init() {
if ( (li = calloc(1, sizeof(libinfo_t))) ) {
li->num = 1;
li->sym[0].name = "foo";
li->sym[0].addr = &foo;
}
}
__attribute__((destructor)) void __free() {
if (li)
free(li);
}
int getinfo(libinfo_t** inf) {
if (!inf)
return -1;
*inf = li;
return 0;
}
char* foo(void) {
return "Hello, World!";
}
main.c
#include <stdio.h>
#include <dlfcn.h>
#include <lib.h>
libinfo_t* inf;
void* hlib;
int (*__getinfo)(libinfo_t**);
char* (*foo)(void);
char* s;
int main(int argc, char** argv) {
if ( !(hlib = dlopen("./lib.so", RTLD_LAZY)) )
return 1;
if ( !(__getinfo = dlsym(hlib, "getinfo")) )
return 2;
if (__getinfo(&inf))
return 3;
if ( !(foo = inf->sym[0].addr) )
return 4;
s = foo();
printf("%p => %s\n", inf->sym[0].addr, s);
return 0;
}
Now compile it (without -nostartfiles):
gcc -I. -o lib.o -c lib.c -Wall -Werror -O3 -fPIC
gcc -o lib.so lib.o -shared
gcc -I. -o main.o -c main.c -Wall -Werror -O3
gcc -o prog main.o -ldl
This printf the same as Test 1: the address of library function foo() and the result of its execution.
I tried to show how can I get shared library function address, but am I right in the second test? Shall I have got some troubles with it?
NOTE: in FreeBSD-8.2 there is no need to use -ldl argument, all dlfcn.h routines are in libc library.
Respectively waithing for any explanations.
That looks fairly standard to me. The only thing that you're using that could pose some problems is that you're using gcc attributes to create a constructor and destructor for your shared library. That may not be entirely portable; it depends on what platforms you care about.
Note that in this specific case there's no need to do something this complicated. The information that you're returning from the shared library in your second example is all known at compile time, so you can just create a static struct with that information and either retrieve the address of the struct with dlsym and poke around in it from the main program or call a known function to return the struct. (The latter is slightly more flexible in some corner cases, but both are fairly flexible.)

C Undefined reference

I have the following code:
main.c
#include "checksum.h"
void main()
{
char *Buf ="GPGGA204502.005106.9813N11402.2921W1090.91065.02M-16.27M";
checksum(Buf);
}
checksum.c
#include <stdio.h>
#include <string.h>
checksum(char *Buff)
{
int i;
unsigned char XOR;
unsigned long iLen = strlen(Buff);
printf("Calculating checksum...\n");
for (XOR = 0, i = 0; i < iLen; i++)
XOR ^= (unsigned char)Buff[i];
printf("%X \n",XOR);
}
checksum.h
#ifndef CHECKSUM_H_INCLUDED
#define CHECKSUM_H_INCLUDED
void checksum(char *Buff);
#endif
When compiling I get the following error:
/tmp/ccFQS7Ih.o: In function `main':
main.c:(.text+0x18): undefined reference to `checksum'
collect2: ld returned 1 exit status
I can't figure out what the problem is?
You are compiling only one file not both. More precisely, you are not linking the files together.
I don't know your compiler, but with gcc, it would be something like this:
gcc -c main.c <-- compile only
gcc -c checksum.c <-- compile only
gcc main.o checksum.o <-- link the two
Edit: To automate this process, take a look at the make program which reads Makefiles.
You could also try
gcc -o program.out main.c checksum.c which will compile and link both files together
I think: in checksum.c, you should include checksum.h.

Trouble using makefile with multiple files in C

Starting to get my head around makefiles for my C programs, but having some trouble when trying to include multiple files. Ignoring the fact that the program below is incomplete (in terms of functionality but not compilation), I'm trying to get this program compiling and running using a make file.
Here is my make file:
main: main.o IntList.o
gcc -o main main.o IntList.o
main.o: main.c
gcc -c -ansi -pedantic -Wall main.c
IntList.o: IntList.c IntList.h
gcc -c -ansi -pedantic -Wall Intlist.c
And here is the error I am receiving:
gcc -c -ansi -pedantic -Wall Intlist.c
gcc -o main main.o IntList.o
ld: duplicate symbol _getNewInt in IntList.o and main.o
collect2: ld returned 1 exit status
make: *** [main] Error 1
The code for the program is below. I'm not sure whether it's the make file or my includes in the program files that are causing problems (or both!)
Any help would be great. Cheers.
Edit: Any tips to steer me in the right direction in terms of modularization would be much appreciated as I'm not sure if I am doing this the best way.
IntList.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Constants */
#define MAX_INTS 10
/* Signed ints can have a maximum of 10 digits. We make the length 11 to
* allow for the sign in negative numbers */
#define MAX_INPUT_LENGTH 11
#define EXTRA_SPACES 2
/* Typedefs / Structs */
typedef struct {
int list[MAX_INTS];
int noInts;
} IntList;
/* Proto Types */
int insertIntToList(int *list);
void shiftList(int offset);
void displayList();
IntList.c
#include "IntList.h"
int getNewInt(int *list)
{
int valid = 0, inputInt;
char inputString[MAX_INPUT_LENGTH + EXTRA_SPACES];
while(!valid)
{
printf("Input an int: ");
valid = 1;
if((fgets(inputString, MAX_INPUT_LENGTH + EXTRA_SPACES, stdin)) != NULL)
{
sscanf(inputString, "%d", &inputInt);
/* Check first that the input string is not too long */
if(inputString[strlen(inputString) - 1] != '\n')
{
printf("\nError: Too many characters entered \n");
valid = 0;
}
printf("\nThe Int: %d", inputInt);
printf("\n");
}
}
}
void shiftList(int offset)
{
}
void displayList()
{
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include "IntList.c"
int main(void)
{
int intList[10];
getNewInt(intList);
return EXIT_SUCCESS;
}
Don't include the .c file in main, include the .h file. Otherwise the code in IntList.c gets compiled both into the IntList.o and the main.o, so you'll get duplicate symbols.
Use this in main.c instead of IntList.c:
#include "IntList.h"
#include "IntList.c"
should be:
#include "IntList.h"
Also (though nothing to do with your problem) I would recommend not using mixed case in the names of source files, as it can lead to portability problems and hard to diagnose "no such file" errors - use all lower case, like the standard library headers do.
Don't #include "IntList.c" into main.c
You should not have:
#include "IntList.c"
in your main program, it should be:
#include "IntList.h"
By including the C file, you create a getNewInt in both your main and IntList object files, which is why you're getting the duplicate definition error when you try to link them together.
main.c should include "IntList.h", not "IntList.c".
If you include IntList.c, the functions in IntList.c will be implemented both in IntList.o and in main.o, which would produce the "duplicate symbol" error you're seeing.
As others have mentioned, you include .h files, not .c files
Also when you compile, you only compile .c files so you should remove any references to .h files in your Makefile

Resources