2

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
Jeff Holt
  • 2,940
  • 3
  • 22
  • 29
  • In the main file you are not importing `stack.c` since you commented it out. – Gerardo Zinno Sep 10 '21 at 09:06
  • @GerardoZinno it is still giving me an error. – donkeykongcodes Sep 10 '21 at 09:09
  • Including source file (i.e. *.c) isn't a good practice. Rather, create a header file with the functions declarations you want to be visible to the other translation units and include this header where it's needed instead. Not including the *.c and including dslib.h is the right thing to do. – Yun Sep 10 '21 at 09:10
  • @Yun like '#include "stack.c" ' and '#include "test.c" '? – donkeykongcodes Sep 10 '21 at 09:18
  • No, do _not_ linclude *.c files. Only include *.h files. That part is correct. I suspect that the problem is a Makefile dependency-thing. Could you try compiling without Make by typing `gcc *.c` (provided this globs exactly the C-files of your project)? – Yun Sep 10 '21 at 09:22
  • Maybe this helps? https://stackoverflow.com/questions/44834931/why-does-the-order-of-prerequisites-matter-in-a-makefile – Yun Sep 10 '21 at 09:24
  • Does this answer your question? [What is an undefined reference/unresolved external symbol error and how do I fix it?](https://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix) – Yun Sep 10 '21 at 09:35
  • @Yun the gcc *.c worked. it even produced a a.out file which ran. Im guessing it is a makefile problem which im not sure how to fix. – donkeykongcodes Sep 10 '21 at 09:36
  • It's definitely a Makefile thing. it's not clear to Make that `test.c` depends on `stack.c`. Maybe I have time to give a more elaborate answer later, but I also wouldn't be surprised if this was a duplicate question. – Yun Sep 10 '21 at 09:40

3 Answers3

4
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.

Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82
3

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.

Jeff Holt
  • 2,940
  • 3
  • 22
  • 29
2

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 */
NeWi-SL
  • 127
  • 1
  • 6