How to fix 'undefined reference' when compiling in C? - c

I'm trying to compile a C program linking two previously created object files but keep getting an 'undefined reference' error.
I'm using Visual Code to write the code and Ubuntu on Windows to compile using a makefile. The two C files, task5.c and reverse.c which have been made into object files both contain #include reverse.h statements which contains the prototypes for the functions in reverse.c.
task5.c
#include <stdio.h>
#include "ctap.h"
#include "reverse.h"
TESTS {
const char *a = "Family";
char *b = reverse(a);
//test 1
ok(string_length(a) == string_length(b), "Strings are the same size");
//test 2
is("ylimaF", b, "Strings match");
}
reverse.c
#include <stdio.h>
#include <stdlib.h>
#include "reverse.h"
char *reverse(const char *str) {
//code
}
int string_length(const char *str) {
//code
}
reverse.h
char *reverse(const char *str);
int string_length(const char *str);
makefile
linked:
gcc -o linked task5.o reverse.o
task5.o
gcc -c -o task5.o task5.c
reverse.o
gcc -c -o reverse.o reverse.c
When I run the command make linked I expect it to be made and return nothing.
But when I run that command I get this error:
cc task5.o -o linked
task5.o: In function `ctap_tests':
task5.c:(.text+0x1abe): undefined reference to `reverse'
task5.c:(.text+0x1ace): undefined reference to `string_length'
task5.c:(.text+0x1adc): undefined reference to `string_length'
collect2: error: ld returned 1 exit status
<builtin>: recipe for target 'linked' failed
make: *** [task5] Error 1

According to this GNU make documentation, the GNU make program will try to use GNUMakefile, makefile or Makefile.
The make program will not try makefile.mk, which means that e.g. make linked will use no makefile and only the default rules.
You can solve this by either renaming your makefile as Makefile (the most common) or makefile; Or by using the -f option to specify the makefile
$ make -f makefile.mk linked

Related

Attempting to link conio to my makefile. make returns cannot find -lconio

I'm writing my first makefile. I wanted to link 2 files together. test.c and main.c. test.c includes a test.h as well as a header file, conio.h.
So far I've tried adding the header file to the paths returned after the failing make command, as well as adding the path to the header file in the command itself. For reference I'm using git bash. To add the make command to git bash I needed to add it directly to the bin folder of gits mingw, but it is looking program files x86 / mingw, which also contains conio.h
Do I need to link it to some kind of library instead. Any help in the matter would be appreciated.
gcc main.o test.o -o test -lconio
C:/Program Files (x86)/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/bin/../lib/gcc/i686-w64-mingw32/8.1.0/../../../../i686-w64-mingw32/bin/ld.exe: cannot find -lconio
collect2.exe: error: ld returned 1 exit status
make: *** [Makefile:7: main] Error 1
main.c
#include "test.h"
int main() {
char c = inputChar();
return 0;
}
test.c
#include "test.h"
#include <conio.h>
void printChar(char casd)
{
_putch(casd);
}
void printString(const char *c) {
for (const char* s = c; *s != 0; s++) {
printChar(*s);
}
printChar('\n');
}
char inputChar() {
char c = _getch();
printChar(c);
return c;
}
test.h
void printChar(char);
void printString(const char *c);
char inputChar();

Error in compiling before linking the object files using gcc

I have source files written in C programming using notepad++ and I am running them from command lines and later i need to link them inorder to generate the .exe file.
Here are the following commands I want to use while generating .exe file
gcc logc.c -o logc
gcc mainc.c -o mainc
gcc -o output logc.o mainc.o
But when i run the following command my compiler is returning with the following error status.
gcc logc.c -o logc
(x86)/mingw-w64/i686-8.1.0-win32-dwarf-rt_v6-rev0/mingw32/bin/../lib/gcc/i686-w64-mingw32/8.1.0/../../../../i686-w64-mingw32/lib/../lib/libmingw32.a(lib32_libmingw32_a-crt0_c.o):crt0_c.c:(.text.startup+0x39): undefined reference to `WinMain#16'
when i run the following command to compile my mainc file
C:\Users\user\AppData\Local\Temp\ccskY3nf.o:mainc.c:(.text+0x31): undefined reference to `Log'
collect2.exe: error: ld returned 1 exit status
And here are my mainc.c and logc.c and logc.h files for your reference
logc.c file is here
#include <stdio.h>
#include "logc.h"
void InitLog()
{
Log("Initializing Log");
}
void Log(const char* message)
{
printf(" %s",message);
}
mainc.c file is here
#include <stdio.h>
#include <conio.h>
#include <stdbool.h>
#include "logc.h"
int main()
{
int x = 5;
bool comparisonResult = x == 5;
if(comparisonResult == 1)
Log("Hello World");
return 0;
}
and logc.h file is here
#ifndef _LOG_H
#define _LOG_H
void InitLog();
void Log(const char* message);
#endif
How can i compile individual source files and then link them and generate an executable file.
Thanks in advance.
You don't create object files, for that you need the -c argument:
gcc logc.c -c
gcc mainc.c -c
gcc -o output logc.o mainc.o
By default gcc will generate an executable file, not an object file. So when you compile logc.c, it tries to make an executable but it can't find the main function so it fails. Similarly with main.c, it tries to make an executable but can't find Log
You need to add the -c option to create object files:
gcc logc.c -c -o logc.o
gcc mainc.c -c -o mainc.o

C makefile undefined-reference error

I am having slight problems with using makefile in C. Ive been following a tutorial in a textbook, but it doesnt seem to want to work. I have three files, message_hider.c, encrypt.h and encrypt.c. When I create a makefile for these files it returns an error, but when I run each command individually it works just fine. Here are my files.
encrypt.c
#include "encrypt.h"
void encrypt(char *message) {
char c;
while (*message) {
*message = *message ^ 31;
message++;
}
}
message_hider.c
#include <stdio.h>
#include "encrypt.h"
int main() {
char msg[80];
while (fgets(msg, 80, stdin)) {
encrypt(msg);
printf("%s", msg);
}
}
encrypt.h
void encrypt(char *message);
Makefile
message_hider: message_hider.o encrypt.o
gcc message_hider.o encrypt.o -o message_hider
message_hider.o: message_hider.c encrypt.h
gcc -c message_hider.c
encrypt.o: encrypt.c encrypt.h
gcc -c encrypt.c
Error message
$ make message_hider
cc message_hider.o -o message_hider
message_hider.o:message_hider.c:(.text+0x17): undefined reference to `encrypt'
message_hider.o:message_hider.c:(.text+0x17): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `encrypt'
/usr/lib/gcc/x86_64-pc-cygwin/4.8.2/../../../../x86_64-pc-cygwin/bin/ld: message_hider.o: bad reloc address 0x0 in section `.pdata'
/usr/lib/gcc/x86_64-pc-cygwin/4.8.2/../../../../x86_64-pc-cygwin/bin/ld: final link failed: Invalid operation
collect2: error: ld returned 1 exit status
<builtin>: recipe for target 'message_hider' failed
make: *** [message_hider] Error 1
$ make message_hider
cc message_hider.o -o message_hider
That is not the rule you've specified in your makefile. First off, it appears to be using cc rather than gcc. Second, there's no mention of encrypt.o in there which is why your link is failing.
Try to explicitly use the makefile, such as with:
make -f Makefile message_hider
It may be that it's picking up a different makefile, one that either has different rules or one that simply relies on the default rules like .c.o.
And, based on your update that:
make -f Makefile message_hider
gives you:
$ make -f Makefile message_hider
make: Makefile: No such file or directory
make: *** No rule to make target 'Makefile'. Stop.
that's the error you get when Makefile does not actually exist.
So you need to check that it's in the current directory, and named exactly as you expect.
That would explain the use of default rules as mentioned earlier, since your makefile isn't actually being picked up.
Another thing to check, though it's probably moot now that we've seen the error above, is that you're actually running the correct make program. Use which make to find out where it is (should be /usr/bin/make on CygWin) and make --version to check the version.

Cuda mixed C project linking

I have a large project in C and i'm trying to integrate some Cuda kernels in it. I'm compiling my c-files with "gcc -c main.c" and my .cu files with "nvcc -c cuda_GMRES.cu" and then I try to link the 2 object files with nvcc: "nvcc -o main.o cuda_GMRES.o" and receive the following error:
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crt1.o: In function
_start':
(.text+0x20): undefined reference tomain'
collect2: ld returned 1 exit status
It's the first time I'm trying to combine cuda with C files and I might have done something wrong.Can someone help me please. I'm on a GPU Cluster with Rocks OS.
My main.c file:
#include <stdio.h>
#include <math.h>
#include "cuda_wrapper.h" //header containing wrapper function
//cuda_GMRES that calls the kernel cuda_dot
int main (int argc,char* argv[])
{
//content
//bla bla bla
//cuda Function call
cuda_GMRES(50);
return 0;
}
My cuda_wrapper.h file:
#ifndef Cuda_GMRES_cuda_wrapper_h
#define Cuda_GMRES_cuda_wrapper_h
//wrapper function declaration
void cuda_GMRES(double a);
#endif
My cuda_GMRES.cu file that contains the kernel calling function:
#include <stdio.h>
#include "cuda_wrapper.h"
#include "cuda_dot.cu"
//kernel declaration
__global__ void cuda_dot();
//kernel calling function
extern "C"
void cuda_GMRES(double a)
{
double b;
double *dev_a;
double *res;
cudaMemcpy(dev_a, &a, sizeof(double), cudaMemcpyHostToDevice );
cuda_dot<<< 1, 1 >>>(*dev_a, res );
cudaMemcpy(&b, res, sizeof(double), cudaMemcpyDeviceToHost );
}
My cuda_dot.cu file that contains the kernel:
__global__ void cuda_dot(double a, double *help)
{
*help=2*a;
}
Your linking command appears to contain a fatal error. Supposing you first compile two objects like this:
gcc -c main.c
nvcc -c cuda_GMRES.cu
you should have two object files main.o and cuda_GMRES.o. You then do this:
nvcc -o main.o cuda_GMRES.o
This command says "link a program file called main.o using cuda_GMRES.o", ie. overwrite main.o. It is for this reason that the linker is complaining about a missing main subroutine, you are not supplying one (and you are destroying the object file which contains one at the same time).
You want something like this:
nvcc -o executable main.o cuda_GMRES.o
where executable is the name of the final linked program, or
nvcc main.o cuda_GMRES.o
which will emit a default linked program called a.out

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