I have the following piece of code which uses ICU macros in order to determine UTF-8 string length:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unicode/utf.h>
size_t utf8_strlen( uint8_t* str, size_t length ) {
int32_t i = 0;
int32_t result = 0;
UChar32 cur;
while( i < length ) {
U8_NEXT( str, i, length, cur );
if( cur < 0 )
return -1;
result++;
}
return result;
}
However, when compiling and linking it as
cc `icu-config --ldflags` test.c
I get the following error:
/tmp/ccaVwSaO.o: In function `utf8_strlen':
test.c:(.text+0x141): undefined reference to `utf8_nextCharSafeBody_48'
collect2: ld returned 1 exit status
The command above expands to cc -ldl -lm -L/usr/lib -licui18n -licuuc -licudata -ldl -lm test.c, and libicuuc does have utf8_nextCharSafeBody_48 defined in it. Why does the linking error happen?
Try:
$ cc test.c $( icu-config --ldflags )
you typically need to list libraries last.
Related
I'm trying to learn c and I implemented a bubblesort function and i decided It would be better idea if i made a library that will contain various sorting algorithms, so I compiled my code with this:
gcc -shared -fPIC -o bin/bsort.o sort/Bubblesort.c
my bubblesort.c is working (and not related to question at all and there is nothing other than bubblesort function there):
// Licensed under public domain with no warranty
void bubblesort(int* array) {
//implemention goes here
}
my sort.h file:
void bubblesort(int* array);
my nsort.c
#include "sort/sort.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
int main() {
int* sortthis = malloc(1000*sizeof(int));
for(int i = 0; i < 1000; i++) {
*(sortthis+i) = random(); //random int is defined somewhere else
}
bubblesort(sortthis);
for(int i = 0; i < 90; i++) {
printf("%d ",*(sortthis+i));
}
free(sortthis);
return 0;
}
my script that i use to compile:
gcc -shared -fPIC -o bin/bsort.o sort/Bubblesort.c
gcc nsort.c sort/sort.h -Lbin/bsort.o -lm -o demo.elf
what could be i'm doing wrong, i tried various things but it didn't work, i kept getting following error:
/usr/bin/ld: /tmp/ccxhd5zd.o: in function `main':
nsort.c:(.text+0x23): undefined reference to `bubblesort'
collect2: error: ld returned 1 exit status
gcc --version (just in case if there is a bug in this version):
gcc (Debian 10.2.1-6) 10.2.1 20210110
You don't put -L before the .o file. -L is for adding directories that -l searches for libraries.
To link with an object file, just add it as an ordinary file argument.
You also don't need to include header files in the compiler arguments. The compiler reads them when it sees #include.
gcc nsort.c bin/bsort.o -lm -o demo.elf
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 */
I wrote an function, which checks, if string of char is palindrome or not.
//pan.c
#include <stdbool.h>
#include "funs.h"
#include <stdio.h>
#include <string.h>
bool palindrom(char napis[])
{
int begin, middle, end, length = 0;
while(napis[length] != '\0')
length++;
end = length - 1;
middle = length;
for (begin = 0; begin < middle; begin++)
{
if(napis[begin] != napis[end])
{
return false;
break;
}
end--;
}
if(begin == middle)
return true;
}
I also created funs.h
//funs.h
#include <stdbool.h>
bool palindrom();
Now, I'm trying to use this function in my main function
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "funs.h"
int main()
{
char text[100];
bool result;
printf("Enter an char: ");
scanf("%s", text);
result = palindrom(text);
if(result)
{
printf("Brawo!\n");
}
else
{
printf("Gówno!\n");
}
return 0;
}
I also created makefile:
# Makefile
all: main
main: main.o pan.o
clang -o main main.o pan.o
main.o: main.c
clang -c main.c
pan.o: pan.c
clang -c pan.c
clean:
rm -f main *.o *~
Everything seems fine and works in single file, but when I try to compile them separately they "don't see" each other. Makefile also seems to work badly, but I can't see any mistakes. Can you help me fix it?
When I try "make" command it returns "makefile:15: *** missing separator. Stop." comment and do nothing.
Did you actually look at line 15 of your makefile? Notice that it's flush against the margin instead of indented by a tab character.
When I'm compiling pan.c with "clang pan.c -Wall --pedantic -std=c11 -o pan" command: 1 warning generated. /usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../x86_64-linux-gnu/crt1.o: In function _start': (.text+0x20): undefined reference to main'
Indeed, your pan.c does not have a main() function. So don't try to compile it by itself. How about
clang main.c pan.c -Wall --pedantic -std=c11 -o pan
When trying to compile a simple parsing program using libxml2, GCC returns this error.
/tmp/ccuq3Hc1.o: In function `main':
xmltesting.c:(.text+0x31): undefined reference to `htmlCreatePushParserCtxt'
xmltesting.c:(.text+0x50): undefined reference to `htmlCtxtReadFile'
xmltesting.c:(.text+0x64): undefined reference to `xmlDocGetRootElement'
collect2: error: ld returned 1 exit status
Code:
#include <stdio.h>
#include <libxml/HTMLparser.h>
#include <libxml/HTMLtree.h>
#include <libxml/tree.h>
#include <libxml/parser.h>
int main()
{
htmlDocPtr doc;
htmlNodePtr org_node;
htmlNodePtr curnt_node = NULL;
htmlParserCtxtPtr parser = htmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL, 0);
doc = htmlCtxtReadFile( parser, "html.txt", NULL, 0);
org_node = xmlDocGetRootElement( parser->myDoc );
for ( curnt_node = org_node; curnt_node; curnt_node = curnt_node->next ) {
if ( curnt_node->type == XML_TEXT_NODE ) {
printf ("%s", curnt_node->content );
}
}
}
It seems to be reading the structs fine, but the functions are not to be found?
Or is something wrong with my code?
You probably simply have to tack an -lxml2 at the end of the gcc build line.
As Dietricg Epp points out in the comments, if your library has the right .pc file pkg-config is the preferred way to get the neccesary flags. You can get both compile and link flags.
$ pkg-config libxml-2.0 --cflags --libs
-I/usr/include/libxml2 -lxml2
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.