This question already has answers here:
'undefined reference' errors when compiling against library
(2 answers)
Closed 10 years ago.
I'm having a problem trying to run the GNU Readline library sample code available in wikipedia. Here it goes:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <readline/readline.h>
#include <readline/history.h>
int main()
{
char* input, shell_prompt[100];
// Configure readline to auto-complete paths when the tab key is hit.
rl_bind_key('\t', rl_complete);
for(;;) {
// Create prompt string from user name and current working directory.
snprintf(shell_prompt, sizeof(shell_prompt), "%s:%s $ ", getenv("USER"), getcwd(NULL, 1024));
// Display prompt and read input (n.b. input must be freed after use)...
input = readline(shell_prompt);
// Check for EOF.
if (!input)
break;
// Add input to history.
add_history(input);
// Do stuff...
// Free input.
free(input);
}
}
I'm working on a restricted environment were readline was not available, so I had to download the sources, compile it and install it to my home dir.
This is the structure inside my home directory:
.local
├── include
│ └── readline
│ ├── chardefs.h
│ ├── history.h
│ ├── keymaps.h
│ ├── readline.h
│ ├── rlconf.h
│ ├── rlstdc.h
│ ├── rltypedefs.h
│ └── tilde.h
└── lib
├── libhistory.a
├── libhistory.so -> libhistory.so.6
├── libhistory.so.6 -> libhistory.so.6.2
├── libhistory.so.6.2
├── libreadline.a
├── libreadline.so -> libreadline.so.6
├── libreadline.so.6 -> libreadline.so.6.2
└── libreadline.so.6.2
The problem is, when I call gcc it throws me an error:
$ gcc hello.c -o hello_c.o -I /home/my-home-dir/.local/include
/tmp/cckC236E.o: In function `main':
hello.c:(.text+0xa): undefined reference to `rl_complete'
hello.c:(.text+0x14): undefined reference to `rl_bind_key'
hello.c:(.text+0x60): undefined reference to `readline'
hello.c:(.text+0x77): undefined reference to `add_history'
collect2: error: ld returned 1 exit status
There is an answer about this here, but I'm not using Netbeans and I'm not quite sure how to specify the path to the library on the command line.
I tried to tell the linker where the libraries are, but the result is still the same:
$ gcc hello.c -o hello_c.o -I /home/my-home-dir/.local/include -Xlinker "-L /home/my-home-dir/.local/lib"
/tmp/cceiePMr.o: In function `main':
hello.c:(.text+0xa): undefined reference to `rl_complete'
hello.c:(.text+0x14): undefined reference to `rl_bind_key'
hello.c:(.text+0x60): undefined reference to `readline'
hello.c:(.text+0x77): undefined reference to `add_history'
collect2: error: ld returned 1 exit status
Any ideas what I might be missing here?
You need to link against the actual library using -lreadline in gcc arguments.
Related
I would like to implement a library that is based on the gobject type system. So every object is a instance of GObjectClass
In the header gwl-registry.h I have:
#define GWL_TYPE_REGISTRY gwl_registry_get_type()
G_DECLARE_DERIVABLE_TYPE(GwlRegistry, gwl_registry, GWL, REGISTRY, GObject)
Which declares the type and the function that obtains a type. This is what I should do according the gobject tutorial: https://developer.gnome.org/gobject/stable/howto-gobject.html If I understand it correctly these macro's should expand to include the instance cast GWL_REGISTRY() and type check macro GWL_IS_REGISTRY(). However both functions rely on the function gwl_registry_get_type().
If I'm not mistaken this should be implemented in the source file gwl-registry.c. Here I define the type using this code:
G_DEFINE_TYPE_WITH_PRIVATE(GwlRegistry, gwl_registry, G_TYPE_OBJECT)
Than this macro should expand to create the GType gwl_registry_get_type().
Using meson I create a library which currently looks like this:
├── data
│ └── xdg-shell.xml
├── include
│ ├── gwl-display.h
│ ├── gwl.h
│ ├── gwl-import.h
│ ├── gwl-registry.h
│ ├── gwl-registry-private.h
│ └── meson.build
├── meson.build
├── src
│ ├── gwayland.c
│ ├── gwl-display.c
│ ├── gwl-registry.c
│ └── meson.build
└── test
├── display-test.c
├── gwayland-test.c
├── meson.build
├── registry-test.c
└── tests.h
The toplevel meson.build looks like:
project(
'GWayland', 'c',
version : '0.1',
default_options : ['warning_level=3']
)
glib_dep = dependency('glib-2.0')
gobject_dep = dependency('gobject-2.0')
wayland_dep = dependency('wayland-client')
# These arguments are only used to build the shared library
# not the executables that use the library.
lib_args = ['-DBUILDING_GWL']
subdir('src')
subdir('include')
# Make this library usable as a Meson subproject.
gwayland_dep = declare_dependency(
include_directories: include_directories('./include'),
dependencies: [glib_dep, gobject_dep, wayland_dep],
link_with : gwayland_shared_lib
)
subdir('test')
pkg_mod = import('pkgconfig')
pkg_mod.generate(
name : 'GWayland',
filebase : 'gwayland',
description : 'Meson sample project.',
subdirs : 'gwayland',
libraries : gwayland_shared_lib,
version : '0.1',
)
The src meson.build looks like:
gwayland_srcs = [
'gwl-display.c',
'gwl-registry.c',
]
gwayland_shared_lib = shared_library(
'gwayland',
gwayland_srcs,
install : true,
c_args : lib_args,
gnu_symbol_visibility : 'hidden',
include_directories : '../include',
dependencies : [glib_dep, gobject_dep, wayland_dep],
)
and the test:
test_sources = [
'gwayland-test.c',
'tests.h',
'display-test.c',
'registry-test.c',
]
test_deps = [glib_dep, wayland_dep]
test_exe = executable(
'gwayland_test',
test_sources,
dependencies: gwayland_dep,
# link_with : gwayland_shared_lib
env : [
'G_TEST_SRCDIR=#0#'.format(meson.current_source_dir()),
'G_TEST_BUILDDIR=#0#'.format(meson.current_source_dir())
]
)
test('gwayland', test_exe)
Currently in the tests I'm calling the casting macro GWL_IS_REGISTRY()
g_assert_true(GWL_IS_REGISTRY(registry));
This leads to the following error:
cc -o test/gwayland_test test/gwayland_test.p/gwayland-test.c.o test/gwayland_test.p/display-test.c.o test/gwayland_test.p/registry-test.c.o -Wl,--as-needed -Wl,--no-undefined -Wl,--start-group src/libgwayland.so /usr/lib/x86_64-linux-gnu/libglib-2.0.so /usr/lib/x86_64-linux-gnu/libgobject-2.0.so /usr/lib/x86_64-linux-gnu/libwayland-client.so -Wl,--end-group '-Wl,-rpath,$ORIGIN/../src' -Wl,-rpath-link,/home/duijn119/github/gwayland/build/src
test/gwayland_test.p/registry-test.c.o: In function `GWL_IS_REGISTRY':
/home/duijn119/github/gwayland/build/../include/gwl-registry.h:30: undefined reference to `gwl_registry_get_type'
collect2: error: ld returned 1 exit status
If I check the library with nm:
nm src/libgwayland.so | egrep 'get_type|new.'
000000000000193f t gwl_display_get_type
0000000000001fcd T gwl_display_new_address
000000000000231f t gwl_registry_get_type
it seems that somehow the gwl_registry_get_type is not exported for use outside of the library, itside the library/compilation unit I can call the function just fine.
Would any one please help me with glib/gobject to tell me what I'm doing wrong, or do I have some issues with meson to build the library and the tests.
You’ve explicitly asked for symbols to not be exported from your library by default:
gnu_symbol_visibility : 'hidden'
Either change that default, or explicitly mark the symbols you want to be exported by using G_MODULE_EXPORT.
You can explicitly mark the gwl_display_get_type() symbol to be exported using
#define GWL_TYPE_REGISTRY gwl_registry_get_type()
G_MODULE_EXPORT
G_DECLARE_DERIVABLE_TYPE(GwlRegistry, gwl_registry, GWL, REGISTRY, GObject)
as the get_type() function is guaranteed to be the first thing emitted by the G_DECLARE_DERIVABLE_TYPE macro.
Currently I have the following project structure, where the libs directory purpose is to store external C libraries that I download from github because they are not available on my OS's repos:
├── cli
│ └── cli.c
├── libs
│ ├── meson.build
│ └── pqueue
│ ├── pqueue.c
│ └── pqueue.h
├── modules
│ ├── algorithms
│ │ ├── a_star.c
│ │ └── a_star.h
│ ├── meson.build
├── meson.build
Where libs/meson.build is:
libpqueue_sources = [
'pqueue/pqueue.c',
]
pqueue_lib = shared_library('pqueue', libpqueue_sources)
pqueue_dep = declare_dependency(link_with: pqueue_lib)
modules/meson.build is:
algs_sources = [
'algorithms/a_star.c',
]
algs_lib = static_library('algorithms',
sources: algs_sources,
include_directories: libs_include_dirs,
dependencies: pqueue_dep)
and meson.build is:
project('graph-search', 'c')
graph_search_include_dirs = include_directories('modules')
libs_include_dirs = include_directories('libs')
subdir('libs')
subdir('modules')
cli_sources = [
'cli/cli.c'
]
executable('cli',
sources: cli_sources,
include_directories : graph_search_include_dirs,
link_with: [algs_lib])
My problem arises when I try to make an #include "pqueue/pqueue.h" inside a_star.h, it says /modules/algorithms/a_star.h:5:10: fatal error: pqueue/pqueue.h: No such file or directory, but when I move the include to a_star.c the error disappears. Sadly I need to include it on the header file because I need to export a struct that uses a type of pqueue.h
Is there a way to include pqueue.h inside a_star.h without using paths like ../../libs/pqueue/pqueue.h?
Because you don't specify libs_include_dirs for cli.c to build, compiler don't know how to search pqueue/pqueue.h.
Change your meson.build to include libs_include_dirs.
diff --git a/meson.build b/meson.build
index 4087a00..3347466 100644
--- a/meson.build
+++ b/meson.build
## -8,5 +8,5 ## cli_sources = [
]
executable('cli',
sources: cli_sources,
- include_directories : graph_search_include_dirs,
+ include_directories : [graph_search_include_dirs, libs_include_dirs],
link_with: [algs_lib])
I am attempting to remove certain directories from my lcov tracefile, but am not having any success. I am attempting to use relative paths, and I am using cygwin. My test framework is cpputest.
My directory structure looks like this
foo_library
$ tree
├── bar
│ ├── bar.c
│ ├── bar.h
│ ├── bar.o
│ └── makefile
├── makefile
├── readme.md
├── foo.c
├── foo.h
├── foo.o
├── baz
│ ├── baz.c
│ └── baz.h
└── test
├── AllTests.cpp
├── bar
│ ├── bar.d
│ ├── bar.gcda
│ ├── bar.gcno
│ └── bar.o
├── lcov.info
├── lcov-filtered.info
├── Makefile
├── foo.d
├── foo.gcno
├── foo.o
├── baz
│ ├── baz.d
│ ├── baz.gcda
│ ├── baz.gcno
│ └── baz.o
├── test_foo.cpp
├── test-lib
│ └── libfoo.a
├── test-obj
│ ├── AllTests.d
│ ├── AllTests.gcda
│ ├── AllTests.gcno
│ ├── AllTests.o
│ ├── test_foo.d
│ ├── test_foo.gcda
│ ├── test_foo.gcno
│ ├── test_foo.o
│ ├── wrap_foo.d
│ ├── wrap_foo.gcda
│ ├── wrap_foo.gcno
│ └── wrap_foo.o
├── foo_tests.exe
├── wrap_foo.c
└── wrap_foo.h
Here is an example
nick test
$ pwd
/cygdrive/C/Work/git/foo_library/test
nick test
$ lcov --capture --directory './' --output-file lcov.info
Capturing coverage data from ./
Found gcov version: 7.3.0
Scanning ./ for .gcda files ...
Found 5 data files in ./
Processing bar/bar.gcda
Processing baz/baz.gcda
Processing test-obj/AllTests.gcda
Processing test-obj/test_foo.gcda
geninfo: WARNING: cannot find an entry for c~#Work#cpputest#include#CppUTest#Utest.h.gcov in .gcno file, skipping file!
Processing test-obj/wrap_foo.gcda
Finished .info-file creation
nick test
$ lcov --list lcov.info
Reading tracefile lcov.info
|Lines |Functions |Branches
Filename |Rate Num|Rate Num|Rate Num
===========================================================================
[/cygdrive/C/Work/git/foo_library/]
bar/bar.c |83.3% 24|66.7% 3| - 0
foo.c |94.0% 100| 100% 4| - 0
baz/baz.c | 100% 5| 100% 1| - 0
test/AllTests.cpp | 100% 3| 100% 1| - 0
test/test_foo.cpp | 100% 131|74.6% 189| - 0
===========================================================================
Total:|96.2% 263|75.3% 198| - 0
nick test
$ lcov --remove lcov.info './bar/*' --output-file lcov-filtered.info
Reading tracefile lcov.info
Deleted 0 files
Writing data to lcov-filtered.info
Summary coverage rate:
lines......: 96.2% (253 of 263 lines)
functions..: 75.3% (149 of 198 functions)
branches...: no data found
Ultimately I just want to produce coverage data of this foo.c file, and I would like to exclude or remove everything else.
I have tried using absolute paths to these directories, like 'cygdrive/C/Work/git/foo_library/test/bar/*', I have also tried
'`pwd`/test/bar/*'
I am also not really sure which paths I should be specifying, the paths to the gcda files, or the path to the source files. I've tried both.
I've also tried using -b ., and -b ../ in my capture and remove commands.
Edit:
I have to run this from the test subdirectory for the paths to work out. The following shows the full paths
nick test
$ lcov -c -d . -b ../ -o lcov.info
Capturing coverage data from .
Found gcov version: 7.3.0
Scanning . for .gcda files ...
Found 5 data files in .
Processing bar/bar.gcda
Processing baz/baz.gcda
Processing test-obj/AllTests.gcda
Processing test-obj/test_foo.gcda
geninfo: WARNING: cannot find an entry for c~#Work#cpputest#include#CppUTest#Utest.h.gcov in .gcno file, skipping file!
Processing test-obj/wrap_foo.gcda
Finished .info-file creation
nick test
$ lcov --list lcov.info --list-full-path
Reading tracefile lcov.info
|Lines |Functions |Branches
Filename |Rate Num|Rate Num|Rate Num
======================================================================================================================
/cygdrive/C/Work/git/foo_library/bar/bar.c |83.3% 24|66.7% 3| - 0
/cygdrive/C/Work/git/foo_library/foo.c |94.0% 100| 100% 4| - 0
/cygdrive/C/Work/git/foo_library/baz/baz.c | 100% 5| 100% 1| - 0
/cygdrive/C/Work/git/foo_library/test/AllTests.cpp | 100% 3| 100% 1| - 0
/cygdrive/C/Work/git/foo_library/test/test_foo.cpp | 100% 131|74.6% 189| - 0
======================================================================================================================
Total:|96.2% 263|75.3% 198| - 0
Edit:
If I do this: $ lcov -r lcov.info '*bar*' '*baz*' '*cpp' -o lcov-filtered.info
it does what I want. However that seems a little heavy handed.
I had the same problem as you excluding folders.
You should remove source code that you don't want to show in the result and add up to the total number of lines in the coverage ratio.
This way of relative paths works for me to exclude paths.
Set the following variable.
testBarSrcPath=pwd/test/bar/*
And then use the variable when you exclude content.
lcov -r lcov.info "$testBarSrcPath" -o lcov-filtered.info
I installed YCM and syntastic for VIM, normally they work fine, but I have problem when it detect some errors in my code, it shows that can NOT find some head files(which is my project head file).
My directory tree shows below:
TOP
├── debug
│ ├── debug.c
│ ├── debug.h
│ ├── debug.mk
│ └── instrument.c
├── driver
│ ├── driver.c
│ ├── driver_ddi.c
│ ├── driver_ddi.h
│ ├── driver.h
│ └── driver.mk
├── include
│ └── common.h
├── libs
├── Makefile
├── mw
│ ├── manager.c
│ └── mw.mk
└── root
├── main.c
└── root.mk
I copied a .ycm_extra_conf.py to the TOP, meanwhile, I will generated tag and cscope file at TOP as well, therefore each time I open file on TOP, like:
howchen#host:~/Work/c/sample/src
-> gvim ./driver/driver.c
to make sure each time I can add tag and cscope file in VIM. The problem is, if I open driver.c, which contain head files: driver.h, driver_ddi.h, debug.h, common.h, code like below:
#include <stdio.h>
#include <stdlib.h>
#include "math.h"
#include "common.h"
#include "debug.h"
#include "driver_ddi.h"
#include "driver.h"
the syntastic or YCM always show it can NOT find common.h and debug.h, other head files are OK.
My YCM and syntastic config part in vimrc file:
" YCM
" let g:ycm_extra_conf_globlist = ['~/.vim/bundle/YouCompleteMe/cpp/ycm/*','!~/*']
let g:ycm_global_ycm_extra_conf = '~/.vim/bundle/YouCompleteMe/cpp/ycm/.ycm_extra_conf.py'
" Syntastic
let g:syntastic_c_checkers=['make']
let g:syntastic_always_populate_loc_list = 1
let g:syntastic_check_on_open=1
let g:syntastic_enable_signs=1
let g:syntastic_error_symbol = '✗'
let g:syntastic_warning_symbol = '⚠'
set statusline+=%#warningmsg#
set statusline+=%{SyntasticStatuslineFlag()}
set statusline+=%*gbar
My .ycm_extra_conf.py write flags variable as:
flags = [
'-Wall',
'-Wextra',
'-Werror',
'-Wc++98-compat',
'-Wno-long-long',
'-Wno-variadic-macros',
'-fexceptions',
'-DNDEBUG',
'-std=c99',
# ...and the same thing goes for the magic -x option which specifies the
# language that the files to be compiled are written in. This is mostly
# relevant for c++ headers.
# For a C project, you would set this to 'c' instead of 'c++'.
'-x', #I don't know if I need remove -x
'c',
'-isystem',
'../llvm/include',
'-isystem',
'../llvm/tools/clang/include',
'-I',
'.',
'-I',
'../driver'
'-I',
'../debug'
'-I',
'../include'
'-I',
'../include'
]
any wrong flags I set?
Moved here from the question.
I found the problem:
flags = [
'-Wall',
'-Wextra',
'-Werror',
'-Wc++98-compat',
'-Wno-long-long',
'-Wno-variadic-macros',
'-fexceptions',
'-DNDEBUG',
'-std=c99',
# ...and the same thing goes for the magic -x option which specifies the
# language that the files to be compiled are written in. This is mostly
# relevant for c++ headers.
# For a C project, you would set this to 'c' instead of 'c++'.
'-x', #I don't know if I need remove -x
'c',
'-isystem',
'../llvm/include',
'-isystem',
'../llvm/tools/clang/include',
'-I./driver',
'-I./debug',
'-I./include',
]
I missed a comma and path should be ./xxx, also neeeeed '-I/usr/include', and '-I/usr/local/include'.
I've got libusb installed on Mac OS X using Homebrew, and is located at
/usr/local/Cellar/libusb
it's tree looks as follows :
.
└── 1.0.9
├── AUTHORS
├── COPYING
├── ChangeLog
├── INSTALL_RECEIPT.json
├── NEWS
├── README
├── TODO
├── include
│ └── libusb-1.0
│ └── libusb.h
└── lib
├── libusb-1.0.0.dylib
├── libusb-1.0.a
├── libusb-1.0.dylib -> libusb-1.0.0.dylib
└── pkgconfig
└── libusb-1.0.pc
I have the following code:
#include <stdio.h>
#include <stdlib.h>
#include <libusb.h>
int main(void) {
puts("USB Test v0.0.1");
//libusb_device **devices;
libusb_context *ctx = NULL;
int result;
result = libusb_init(&ctx);
if (result < 0) {
puts("USB initialization error!");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
...but compilation yields the following:
22:08:26 **** Incremental Build of configuration debug for project usb_test ****
make all
Building target: usb_test
Invoking: MacOS X C Linker
gcc -L/usr/local/Cellar/libusb/1.0.9/lib -o "usb_test" ./src/usb_test.o -l/usr/local/Cellar/libusb/1.0.9/lib/libusb-1.0.a
ld: library not found for -l/usr/local/Cellar/libusb/1.0.9/lib/libusb-1.0.a
collect2: ld returned 1 exit status
make: *** [usb_test] Error 1
22:08:26 Build Finished (took 68ms)
Why isn't it finding the libusb library?
Somewhere you have a wrong linker flag.
-l/usr/local/Cellar/libusb/1.0.9/lib/libusb-1.0.a
Should just be:
/usr/local/Cellar/libusb/1.0.9/lib/libusb-1.0.a
In this case you do not need to specify the linker search path, so
-L/usr/local/Cellar/libusb/1.0.9/lib is not needed.
If you don't want to link statically to that libusb-1.0.a, but link to the .dylib, you need to keep -L/usr/local/Cellar/libusb/1.0.9/lib and replace
-l/usr/local/Cellar/libusb/1.0.9/lib/libusb-1.0.a
with
-lusb-1.0