I have these 2 c file and a header file. All these files are built by a Makefile.
mysql_storage.h
#include <stdio.h>
#include <mysql.h>
#include <glib/gstdio.h>
#if 1
typedef enum {
STORAGE_OK = 0,
STORAGE_NO_SUCH_USER,
STORAGE_INVALID_PASSWORD,
STORAGE_ALREADY_EXISTS,
STORAGE_OTHER_ERROR/* Error that isn't caused by user input, such as
a database that is unreachable. log() will be
used for the exact error message */
} storage_status_t;
typedef enum
{
MYSQL_PASS_CHECK_ONLY = -1,
MYSQL_PASS_UNKNOWN = 0,
MYSQL_PASS_WRONG,
MYSQL_PASS_OK
} mysql_pass_st;
#endif
static void mysql_storage_init( void );
static void mysql_storage_deinit( void );
static storage_status_t mysql_storage_load(const char *password );
static storage_status_t mysql_storage_check_pass( const char *nick, const char *password );
static storage_status_t mysql_storage_save( int overwrite );
static storage_status_t mysql_storage_remove( const char *nick, const char *password );
mysql_storage.c
#include "mysql_storage.h"
MYSQL *mysql;
static void mysql_storage_init( void ) {
if (mysql_init(mysql) == NULL)
fprintf( stderr, "Can not initialize MySQL. Configuration won't be saved.");
if (!mysql_real_connect(mysql, "localhost", "USERNAME", "PASSWORD", NULL, 3306, NULL, 0))
fprintf( stderr, "%s\nConfiguration won't be saved.", mysql_error(mysql));
if (mysql_select_db(mysql, "DATABASENAME"))
fprintf( stderr, "%s\nConfiguration won't be saved.", mysql_error(mysql));
}
static void mysql_storage_deinit( void ) {
if(mysql!=NULL)
mysql_close(mysql);
}
static storage_status_t mysql_storage_check_pass( const char *nick, const char *password ){ return STORAGE_OTHER_ERROR;}
static storage_status_t mysql_storage_load(const char *password ){ return STORAGE_OTHER_ERROR;}
static storage_status_t mysql_storage_save( int overwrite ){ return STORAGE_OTHER_ERROR;}
static storage_status_t mysql_storage_remove( const char *nick, const char *password ){ return STORAGE_OTHER_ERROR;}
main.c
#include<stdio.h>
#include "mysql_storage.h"
int main(){
// connect mysql
mysql_storage_init();
// check a password
printf("check password: %d\n:", mysql_storage_check_pass("hello", "world"));
// close mysql
mysql_storage_deinit();
}
Lastly the Makefile
CFLAGS=-I/usr/include/mysql -DBIG_JOINS=1 -fno-strict-aliasing -g -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I.
LIBS=-L/usr/lib/x86_64-linux-gnu -lmysqlclient -lpthread -lz -lm -lrt -ldl -lglib-2.0 -L.
CC=gcc
all: main
clean:
rm main *.o
main: mysql_storage.o main.o
$(CC) main.o mysql_storage.o $(LIBS) -o main
.c.o:
$(CC) -c $(CFLAGS) $<
When I make, I get this error.
gcc main.o mysql_storage.o -L/usr/lib/x86_64-linux-gnu -lmysqlclient -lpthread -lz -lm -lrt -ldl -lglib-2.0 -L. -o main
main.o: In function `main':
/home/shiplu/projects/mysql_interface/main.c:8: undefined reference to `mysql_storage_init'
/home/shiplu/projects/mysql_interface/main.c:11: undefined reference to `mysql_storage_check_pass'
/home/shiplu/projects/mysql_interface/main.c:15: undefined reference to `mysql_storage_deinit'
collect2: ld returned 1 exit status
As you can see I am linking main.o and mysql_storage.o. So it should not throw undefined reference error. What is the problem here?
You declared your functions
mysql_storage_initasstatic, meaning they have internal linkage — this means they are not visible to other translation units.Since you need to call them from other object files, you should instead declare them to have external linkage by omitting the
statickeyword in their declarations and definitions. The prototypes in the header file may optionally declare themextern, but that is not required, since the linkage is external by default.