PostgreSQL external C function link failed on Mac OSX - c++

I'm trying to build an external PostgreSQL function on OSX 10.11 with both clang and gcc, but link failed with the following errors:
c++ -I/usr/local/Cellar/postgresql/9.5.3/include/server -fpic -c ./main.c
c++ -shared -o ttt.dylib main.o
Undefined symbols for architecture x86_64:
"_deconstruct_array", referenced from:
_psql_nearest in main.o
"_elog_finish", referenced from:
_psql_nearest in main.o
"_elog_start", referenced from:
_psql_nearest in main.o
"_get_typlenbyvalalign", referenced from:
_psql_nearest in main.o
"_pfree", referenced from:
_psql_nearest in main.o
"_pg_detoast_datum", referenced from:
_psql_nearest in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
It looks like I need to link my library with some of PostgreSQL libraries. What are these libraries?
main.cpp:
extern "C" {
#include <postgres.h>
#include <fmgr.h>
#include <utils/array.h>
#include <utils/lsyscache.h>
#include <catalog/pg_type.h>
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
PG_FUNCTION_INFO_V1(psql_nearest);
Datum psql_nearest(PG_FUNCTION_ARGS) {
if(PG_ARGISNULL(0) || PG_ARGISNULL(1)) {
elog(ERROR, "DOC2VEC: NULL INPUT DATA");
PG_RETURN_NULL();
}
ArrayType *_docVector = PG_GETARG_ARRAYTYPE_P(0);
Oid elTypeVals = ARR_ELEMTYPE(_docVector);
if (elTypeVals != FLOAT4OID) {
elog(ERROR, "DOC2VEC: INVALID INPUT DATA TYPE");
PG_RETURN_NULL();
}
int16 typeLenVals = 0;
bool typeByValVals = false;
char typeAlignVals = char(0);
get_typlenbyvalalign(elTypeVals, &typeLenVals, &typeByValVals, &typeAlignVals);
Datum *inputVals;
bool *nullVals;
int nVals;
deconstruct_array(_docVector, elTypeVals, typeLenVals, typeByValVals, typeAlignVals, &inputVals, &nullVals, &nVals);
pfree(inputVals);
pfree(nullVals);
PG_RETURN_NULL();
}
}

Thanks to PostgreSQL developers, they explained me the difference in Linux and OSX linking of external functions.
Instead of -shared you need -bundle -bundle_loader /path/to/postgres,
and there are some other linker flags that are advisable too.
Also, PostgreSQL expects the file extension for loadable modules to be .so even on OSX.
It's usually better to use PGXS to build extensions, instead of
learning such details for yourself.
Or you can crib from one of the extensions in the contrib/
source tree.

If you need to link, you will need the -L flag to point the linker to the path where the postgres libraries are located (the linker equivalent of the -I compiler flag). and the -l flag to actually link the libraries (one for each library); the library name without the lib prefix and without the extension.
In your case, something along the lines of -L/usr/local/Cellar/postgresql/9.5.3/lib -lpostgres
(There's a variety of library files in that directory; try -lpg to start with.
The reference to _pfree in your error message also suggest to link pgcommon, which contains the implementation of pgree (at least when using nm libpgcommon.a).
)
You may want to read up a bit more on compiling and linking in general; you do the right thing for compiling with the -I flag, but oddly then miss out on the linking step. And learning about make and Makefiles will come in handy.
I also don't understand the extern "C" { part for a .c file, which is clearly a C-only file. extern "C" is usually used in C++ files for compatibility with C.

Related

How to use the fmt library without getting "Undefined symbols for architecture x86_64"

I'm trying to use the fmt (https://github.com/fmtlib/fmt) formatting header library in my c++ project.
I've added the path to the core header file at the top of my main file like so:
#include "../third_party/fmt/core.h"
but when I try to call any function like:
string message = fmt::format("The answer is {}", 42);
I get the following error:
Undefined symbols for architecture x86_64:
"std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > fmt::v5::internal::vformat<char>(fmt::v5::basic_string_view<char>, fmt::v5::basic_format_args<fmt::v5::buffer_context<char>::type>)", referenced from:
std::__1::basic_string<std::__1::enable_if<internal::is_string<char [17]>::value, fmt::v5::internal::char_t<char [17]>::type>::type, std::__1::char_traits<std::__1::enable_if<internal::is_string<char [17]>::value, fmt::v5::internal::char_t<char [17]>::type>::type>, std::__1::allocator<std::__1::enable_if<internal::is_string<char [17]>::value, fmt::v5::internal::char_t<char [17]>::type>::type> > fmt::v5::format<char [17], int>(char const (&) [17], int const&) in main.cpp.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [main] Error 1
make[1]: *** [CMakeFiles/main.dir/all] Error 2
make: *** [all] Error 2
I'm not sure how to use this as this is how I have used other header libraries in the past such as cxxopts. Any help would be appreciated!
You should link with the fmt library or use the optional header-only mode.
For example, if you have the file test.cc:
#include <fmt/core.h>
int main() {
fmt::print("The answer is {}.", 42);
}
You can compile and link it with gcc:
g++ -std=c++11 test.cc -lfmt
From a comment in #vitaut's answer, if you change your #include line from this:
#include "../third_party/fmt/core.h"
to this:
#include "../third_party/fmt/format.h"
it will cause the code to be compiled in "header-only mode", and you won't need to change your build process to compile and link in the {fmt} library.
I'm working on Mac, and I did not realize that you can install the library using brew. It appears at the end of the page. I have been dealing with symbol errors all evening, and I'm not sure that all my problems were related to the build process. The compiling process was also not working properly.
The paths where the library is installed are: /usr/local/include and /usr/local/lib.
I'm using g++-11 to build my project and this instruction works for me:
g++-11 -std=c++20 -I/usr/local/include -L/usr/local/lib -lfmt main.cpp -o main
The only problem is that it works partially. It works fine with print:
fmt::print("Don't {}!\n", "panic");
But it breaks using format:
fmt::format("Don't {}!\n", "panic");
I'm missing something, but I'm not sure what.
By the way, if you are using VSCode, you can create a c_cpp_properties.json into your .vscode folder and add the include path for the headers.
{
"includePath": [
[...],
"/usr/local/include/"
],
}
Not sure if this is related to your case, but I hope it helps.

boost::filesystem Undefined symbols for architecture x86_64

I am very new with using GNU. I am trying to start using the boost filesystem library, and I keep getting these errors. I am trying to get the current working directory, by using boost::filesystem.
My code:
boost::filesystem::path full_path( boost::filesystem::detail::current_path() );
cout << "Current path is : " << full_path << endl;
My command:
g++ -I boost_1_58_0 main.cpp -o example
Result:
Undefined symbols for architecture x86_64:
"boost::filesystem::detail::current_path(boost::system::error_code*)", referenced from:
_main in main-1c56eb.o
"boost::system::system_category()", referenced from:
___cxx_global_var_init2 in main-1c56eb.o
"boost::system::generic_category()", referenced from:
___cxx_global_var_init in main-1c56eb.o
___cxx_global_var_init1 in main-1c56eb.o
ld: symbol(s) not found for architecture x86_64
Can someone please explain what the error is asking for? What did I do wrong?
boost.filesystem is not a header-only library. You have to link to the library using -L and -l flags. (And make sure the library is already properly built). You need to link to both boost_system and boost_filesystem libraries.
The command line could look like:
g++ -Iboost_1_58_0 -Lboost_1_58_0/lib/ -lboost-filesystem -lboost_system main.cpp -o example
(replace the -L argument with the path where the libboost-filesystem.so file resides)
Then, before you are able run the executable, you have to let the loader know where to look for the libraries. You shell be able do that using the following command:
export DYLD_LIBRARY_PATH=/path/to/boost/bib:$DYLD_LIBRARY_PATH
To make it automatic, I would recommend using a build system like cmake instead of just a command line.

Setting C++ compile flags in xcode

I faced with the same issue for this question: Undefine symbols for architecture x86_64 using FFTW
And I tried to use flag -L and -l for C++ in xcode, but it doesn't work
Here is the error log:
clang: warning: -lsndfile: 'linker' input unused
clang: warning: -lfftw3: 'linker' input unused
clang: warning: argument unused during compilation: '-L/usr/local/lib'
Undefined symbols for architecture x86_64:
"_fftw_destroy_plan", referenced from:
_main in main.o
"_fftw_execute", referenced from:
_main in main.o
"_fftw_plan_dft_r2c_1d", referenced from:
_main in main.o
"_sf_close", referenced from:
_main in main.o
"_sf_open", referenced from:
_main in main.o
"_sf_read_double", referenced from:
_main in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
But if I compile with gcc in command line, it works well.
gcc -I/Users/sr2/Documents/Soft/fftw-3.3.4 -I/usr/local/include
-L/usr/local/lib -lfftw3 -lsndfile main.c -o fft_sample
where am I wrong?
Instead of putting these under "Other C/C++ Flags", they should go under "Other Linker Flags" (in the Linking section).
(Note that my XCode is old, so it may be slightly different for your version.)
You might wonder, why is this necessary?
Well, when you build your project, there are several stages to go through. The most basic breakdown is into compiling and linking. (They could perhaps be broken down further, but that's the important distinction here.)
The compiler takes a source file (eg, example.cpp) and outputs an object file (such as example.o). An object file is not executable. When compiling, the compiler generally only knows about the one source file that it's currently processing. Thus the compiler doesn't need to know which libraries you're using - all it needs to know is where the header files are.
The linker takes one or more object files and combines them together to create an executable binary. At this point, it must also resolve any external symbols not defined in your code - for example, symbols defined in an external library. For that reason, the linker needs to know about any libraries you're using.
The compiler does not know what to do with an -l or -L flag - they're not relevant to the process of compiling your code into an object file.
When you invoke gcc from the command-line like you demonstrated, it automatically invokes the linker for you and forwards those -l and -L flags to it. Because of this, no object file is produced on disk, and you get an executable file.
However, when you build through XCode, it does things a little differently. It invokes the compiler once for each of your source files, producing an object file like I described above. (This is the reason why you can specify extra compiler flags for specific source files in the Build Phases -> Compile Sources section.) Because the compiler has been asked to produce an object file, it does not invoke the linker, and since you're trying to pass it flags that should be forwarded to the linker, you get that warning that the flags are not used.
Once all the source files have successfully compiled, XCode next invokes the linker directly to combine them all into a single executable binary. This is the stage that needs to know about your libraries. (Incidentally, in any large project, this method is generally preferable even if you're not using XCode.)
You need probably add
-lstdc++
to the Other Linker Flags in Build Settings of your Project.

Cannot compile LibOTR

I am trying to use libotr but I have the following problem when attempting to compile a very basic library initialisation.
#include <libotr/proto.h>
int main(int argc, char const *argv[])
{
OTRL_INIT;
// OtrlUserState userstate = otrl_userstate_create();
return 0;
}
I am compiling it with the following command:
g++ main.cpp -o main -L /usr/local/lib/ -lotr
But for some reason I am getting:
Undefined symbols for architecture x86_64:
"otrl_init(unsigned int, unsigned int, unsigned int)", referenced from:
_main in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [bin/bin] Error 1
I explicitly checked and the library does indeed has the following symbols.
After a quick observation I noticed that libotr is using the C type name mangling and the problem is resolved just by adding the following lines to the library's include clause:
extern "C" {
#include <libotr/proto.h>
}
If you have similar problem just list the symbols of a library with the nm utility and check whether the symbol names begin with one or two underscores: _foo is C style, while __foo is C++ style.
P.S. I posted this since it took me a while to figure it out. I hope this question + answer would save you some time.

Trouble setting up Lua in Xcode

How can I include Lua in my project in Xcode?
I have installed Lua via the instructions on the website (curl, extract, make macosx install, etc).
I can reference lua
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
But when I go to use it, I get an error (even writing something as simple as the following)
lua_State *L = luaL_newstate();
lua_close(L);
It tells me :
Undefined symbols for architecture x86_64:
"_luaL_newstate", referenced from:
_main in main.o
"_lua_close", referenced from:
_main in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Any advice would be much appreciated. If you need further information, let me know and I can edit it in. Thanks!
EDIT:
Added the -llua flag (SFML included the /usr/local/lib and include). Now getting "ignoring file /usr/local/lib/liblua.a, file was built for archive which is not the architecture being linked (i386): /usr/local/lib/liblua.a"
EDIT2:
I changed Base SDK to Latest OS X (OS X 10.9) and Build Active Architecture Only to "Yes" and now it will compile.
In Xcode, select < ProjectName > with blue icon on top of the left pane (where all the sources are), then in main window select a target under Targets. In Build Settings tab, select All instead of Basic and set following parameters:
Other Linker Flags = -llua
Header Search Paths = /usr/local/include
Library Search Paths = /usr/local/lib
Assuming Lua headers were installed in /usr/local/include, and liblua.a in /usr/local/lib.
You may also use search field to find them.