-
Notifications
You must be signed in to change notification settings - Fork 243
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
undefined reference to pqxx::argument_error::argument_error
#732
Comments
btw, I did standard building of the lib:
|
There are several possible causes of link errors. If you built libpqxx by autotools (configure script, |
I have just one version of libpqxx - 7.8.2
It compiles without "-std=c++20" if I switch off std::chrono::year_month_day variables. |
Do you mean mixing multiple C++ versions? It will not work.
|
No. I mean my C++ refers to g++13 as default version of the compiler. |
And did you specify the environment variable Also, any of the environment variables will be referenced when running See also: https://github.com/jtv/libpqxx/blob/7.8.1/BUILDING-configure.md#cheat-sheet |
My guess is that it's an inconsistency in detected |
By the way, note that it's best to set |
@Neofitum I can't reproduce the problem with current Debian unstable (gcc 13). Is it possible that the location where |
I'm getting this error when building pqxx library with using GCC 13.2.1 |
This smells like an ODR violation (IFNDR). Can you compile both with the same version? |
when they use the same version (either both using 17 or both using 20) it successfully compiles |
That's what I'd expect. Question is: did a difference in versions sneak into @Neofitum's build? That can happen, for instance, when setting |
I don't know what his build does, I got this error independently from him. |
Guys, sorry for the delay with answer. Now, my source compiles together with <pqxx/pqxx>, std::chrono inside and with -std=c++20 flag. So, it means the library building must be made with -std=c++20 flag if your compiler gcc version is 13 and\or your compiler supports c++20. Thank you all and @tt4g |
Right. By default you should get whatever your compiler decides. (I'm a little surprised to be honest to see that that's still C++17 in gcc 13.) |
For those who came here because the latest Arch linux package with libpqxx 7.8.1+ suffers from this issue and need a quick fix, here is an updated PKGBUILD with C++20 flag enabled, although it is hardly a permanent solution. |
Hi, I have a very simple code example:
and compile this file with
and the compilation succeeds. When I compile the code with
I get this error
My compiler is:
I need C++20 for variuos reasons in the project, so compiling with C++17 is not an option for me. |
@acwn1976 Do not get the package from Debian, build libpqxx manually. |
I agree with what @tt4g said. The problem with using a prepackaged library in C++ is that you're bound to have different compile settings than those that were used to build the packaged library. And there's just not much that can be done about it. It'd be easy to say "just use the compiler's defaults," but those will change with some major compiler upgrades. And then of course, the defaults may not even be what you need. |
I understand the point you are making, but it worked before with the old version. And I am using other C++ libraries (all default Debian packages) and I don't have the problem with them. |
Alright then. I'll have to go back to writing more config into a header at configure time. I'd like to avoid duplicating checks between build systems, of course. Perhaps I can run the compiler in a way that tells me all defined macros, and sort it out from there in a single python script. |
pqxx::argument_error::argument_error
I'm experimenting with an approach where a python script generates C++ code which in turn, when compiled and run, spits out a C++ configuration header. It'll be faster and easier to scale than maintaining all those feature tests, but it will also complicates cross compilation. |
We're getting bug reports (e.g. #732) for situations where people have a libpqxx compiled as C++17 but an application compiled as C++20, or _vice versa._ Generally it's probably not wise to link C++17-compiled code to code compiled as C++20. But two things I did exacerbate the problem: 1. I moved a bunch of C++ feature checks to compile time, using C++20's feature test macros. It looked like a much cleaner, easier way forward with reduced maintenance overhead. 2. Usage of C++20's `std::source_location` _when present_ affects the ABI. So effectively there's one ABI with, and one without. I see that mostly as the price of doing libraries in C++ — it's generally dangerous to package library binaries, unless they've been designed to be compatible, or they come as a range of binaries for various compilers, versions, and configurations. And the real problem is that _these two changes interacted._ The detection of support for `std::source_location` happened at compile time. And so if you compile libpqxx in C++17 (without this feature) and the application in C++20 (with this feature), the two will not be link-compatible! In this first commit I'm prototyping a new approach that I hope will combine the ease of maintenance of feature test macros with the ABI stability of a configuration header. Configuration speed should lie somewhere inbetween: no more compiling separate little checks for every individual C++ feature. But it's not easy. There are 2 orthogonal binary choices, leaving me with 4 scenarios to support: * Autoconf vs. CMake * Cross-compiled vs. native. How does cross compilation factor into it? It works like this: I need to check C++ feature test macros. I check them in C++. But I don't want to keep editing that C++ code for every feature — there's a repetitive preprocessor dance that I don't think I could simplify to one simple line of code, because I'd need to pass macro names as parameters to macros. So, I write a minimal config file and run it through a Python script that generates the C++ code for me. Then I have the build configuration machinery compile _and run_ that C++ code, and generate the configuration header. Yes, alright, but how does cross compilation factor into it? First, if you're cross-compiling, it's not a given that you can _run_ the binary you produce on the same system! The whole point is that the two systems are different. And two, you'll have a native compilation environment but there's no guarantee that it will resemble the cross compilation environment at all. So if you compile a binary to run locally, you may get very different results. So for cross-compilation, the Python script just generates a minimal configuration header that just has all features disabled. And in this first commit I've got that working for autoconf. But I'm still struggling with CMake (thanks @KayEss for helping with this). If it gets too difficult, I may go a different route: generate C++ code from Python, but only run it through the preprocessor. (I believe autoconf has a standard, portable way of running the preprocessor; let's hope CMake has one as well.) The output will still C++ code, but now it's been preprocessed, so hopefully it'll be possible to tell portably which features are present. And ironically, I think I'd then have to have another Python script to _postprocess_ the preprocessed code and turn it into a ready-to-use config header.
It's harder than I thought. It would be relatively easy to generate a C++ file that checks the feature flags; run it through the preprocessor; and then write a config header based on the output. Should work fine even for cross compilers. But:
Tempted to define my own "the option to turn the compiler into a preprocessor" variable... I'll continue pushing the other solution I've been working on: generate some C++ code that checks the feature flags,compile and run it, and have that spit out a config header. Does mean defaulting to all features disabled when cross-compiling, and I have yet to make the thing work for CMake. |
@jtv CMake does not include a preprocessor, but you can use other features to do something similar. See: https://stackoverflow.com/a/37862193 It is important to note that CMake's For example, look at the following code set(pqxx_cxx_features_header include/pqxx/cxx_features.hxx)
add_custom_command(
OUTPUT ${pqxx_cxx_features_header}
COMMAND python tools/generate_checks.py cxx_features.txt --dummy
DEPENDS tools/generate_checks.py cxx_features.txt
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
add_library(pqxx ${SOURCE_FILES} ${pqxx_cxx_features_header}) There are other options such as |
I'm currently using GCC 13.1, and I'm building with vcpkg. I encountered a similar error related to pqxx::conversion_overrun::conversion_overrun. The std::source_location parameter was enabled in the header but not in the compiled library. As a quick and dirty solution (I don't care about std::source_location info), I modified the internal/cxx-features.hxx file by setting #define pqxx_have_source_location to 0 in all cases. My project then linked correctly. Hope that helps! |
@tt4g thanks, I have it down now to the point where it works with autotools, and I just need to get it to work with CMake. For that, I'll need to mirror what I did for autotools:
|
I pretty much don't know how to do any of that with CMake. Any pointers you could give me? I know The preprocessor run and the post-processing need to happen when the user configures a build. I hope it will help that all this now only happens during that one stage. |
@jtv Generating files in the CMake configuration step is a tricky task (compared to autotools). First, I would like to explain the CMake steps, as I think it is important to familiarize yourself with each step of CMake. configure-step: parses
It is important to note that CMake generates project files that are buildable by native build tools, but leaves the building to the native build tools. In autotools, The The best match for this case would be
Another solution that exists in CMake is |
@tt4g might it be possible then to use |
@jtv One method is to set the macro to a variable by
See also: https://stackoverflow.com/questions/70113597/does-filegenerate-resolve-variables |
But will that work for all of these checks in one go? I'd like to get out of compiling a separate check for each individual feature. |
Since If compilation errors do not occur, it may be possible to determine this by outputting a message with Example:
#if defined(__cpp_lib_ssize) || __cpp_lib_ssize
#pragma message "__cpp_lib_ssize"
#endif
int main()
{
return 0;
}
execute_process(
COMMAND "<BUILD_COMMAND>"
RESULT_VARIABLE BUILD_RETURN_CODE
OUTPUT_VARIABLE BUILD_STDOUT
)
if (BUILD_SUCCESS_OR_FAILURE
if(BUILD_RETURN_CODE AND NOT BUILD_RETURN_CODE EQUAL 0)
message(FATAL_ERROR "Build failed")
endif()
if(BUILD_STDOUT MATCHES "__cpp_lib_ssize")
set(SUPPORT_SSIZE TRUE)
end |
I was thinking more along the lines of generating the header as a side effect. But I'm giving up on the idea. I think I'll just have to go with generating individual checks when I run Presumably there's a way that I can make |
Do you mean generate CMake configuration? |
Thanks @tt4g — yes that's what I meant. I'll use |
This is yet another attempt at #732: go back to writing all feature test macros to a config header, so that we can build libpqxx itself and the client application against the same version of the language — even if the user actually builds them with different options that may affect the feature set. Things I wanted for this work: 1. Less of that repetitive configuration. It's tedious and error-prone. 2. Reduced risk of inconsistency between autoconf and CMake. 3. Portability. 4. Simple way to add a feature check based on a C++ feature test macro. 5. Reasonable simplifity. 6. Fast build configuration. I think this solution satisfies most of these. A new configuration file `cxx_features.txt` lets me define features that we detect simply by checking a C++ feature test macro. (We'll still need to enter each libpqxx feature macro that we want to expose into `configitems`.) A first Python script, `generate_cxx_checks.py` generates the C++ code snippets that check for each of the C++ feature check macros. It just adds those to `config-tests/`. The C++ files inside `config-tests/` now have names that correspond _directly_ to the libpqxx feature macros. It eliminates the pointless separate file name, but also, it lets me generate autoconf and CMake config based on just the file names! Then, a second script `generate_check_config.py` produces pieces of autoconf and CMake configuration to actually run these checks. The respective main configurations use include directives to incorporate these configs. These pieces of configuration will reference both the pre-existing, hand-written feature test snippets, and the ones we just generated from C++ feature test macros. At this stage there's no difference between the two kinds. I believe this is as portable as it ever was, because nothing really changes structurally. Yes, the scripts are tailored for recent Python language versions, but I think that's about it. Of course the C++ feature test macros were introduced in C++20 so they're not going to do much good for C++17. But that should stop mattering soon, as we transition to C++20 as the minimum language version. I believe the new system is not the simplest thing, but is easier to manage than all those manual compilation checks across two build systems. That was just painful. And who knows, some day this new approach may support adding yet another build system. The only thing that hasn't improved is build configuration speed. The only positive thing I can say there is that the new mechanism generates all the extra files during `autogen.sh`, so that part shouldn't affect build configuration speeds. But it's not going to be as fast as my last plan for this work. (That experiment checked all the C++ feature test macros by running a single piece of generated C++ code through the preprocessor, and generating a new config header from it.)
I think I finally have something working for this: #747. |
I'm pretty satisfied with #747 so... last chance to voice any concerns about it. :-) It's both a conservative and a radical approach: Conservative — produces the same config header that we used to have before we had this problem. Radical — streamlines maintenance of the build config logic and does make it very easy to add new configuration items based on C++ feature test macros. |
@tt4g, @KayEss — I think this PR solves the problem: #747. Lots of changes, but it boils down to: the old way of working, but with a bunch of configuration in autoconf/cmake automated, and a new config file so I can easily define feature macros in the config header based on the C++ standard feature test macros. |
@jtv I had checked the PR changes several times. |
Generate feature tests, in two stages. This is yet another attempt at #732: go back to writing all feature test macros to a config header, so that we can build libpqxx itself and the client application against the same version of the language — even if the user actually builds them with different options that may affect the feature set. Things I wanted for this work: 1. Less of that repetitive configuration. It's tedious and error-prone. 2. Reduced risk of inconsistency between autoconf and CMake. 3. Portability. 4. Simple way to add a feature check based on a C++ feature test macro. 5. Reasonable simplifity. 6. Fast build configuration. I think this solution satisfies most of these. A new configuration file `cxx_features.txt` lets me define features that we detect simply by checking a C++ feature test macro. (We'll still need to enter each libpqxx feature macro that we want to expose into `configitems`.) A first Python script, `generate_cxx_checks.py` generates the C++ code snippets that check for each of the C++ feature check macros. It just adds those to `config-tests/`. The C++ files inside `config-tests/` now have names that correspond _directly_ to the libpqxx feature macros. It eliminates the pointless separate file name, but also, it lets me generate autoconf and CMake config based on just the file names! Then, a second script `generate_check_config.py` produces pieces of autoconf and CMake configuration to actually run these checks. The respective main configurations use include directives to incorporate these configs. These pieces of configuration will reference both the pre-existing, hand-written feature test snippets, and the ones we just generated from C++ feature test macros. At this stage there's no difference between the two kinds. I believe this is as portable as it ever was, because nothing really changes structurally. Yes, the scripts are tailored for recent Python language versions, but I think that's about it. Of course the C++ feature test macros were introduced in C++20 so they're not going to do much good for C++17. But that should stop mattering soon, as we transition to C++20 as the minimum language version. I believe the new system is not the simplest thing, but is easier to manage than all those manual compilation checks across two build systems. That was just painful. And who knows, some day this new approach may support adding yet another build system. The only thing that hasn't improved is build configuration speed. The only positive thing I can say there is that the new mechanism generates all the extra files during `autogen.sh`, so that part shouldn't affect build configuration speeds. But it's not going to be as fast as my last plan for this work. (That experiment checked all the C++ feature test macros by running a single piece of generated C++ code through the preprocessor, and generating a new config header from it.)
Thank you! I just merged it. Once we get #726 out of the way I think we'll be ready to release 7.9.0. |
@Neofitum @Enhex @tt4g @FloopCZ @acwn1976 @KayEss Some blockers for the next release have cleared up in recent days, so hoping to release 7.9.0 soon, and hopefully the problem won't happen with that. However in the grander scale, we're still stuck with the problem that all package managers encourage us to link things together that may or may not actually be compatible, because of different language versions etc. |
@jtv I think that compilation options for libraries provided by repositories should be devised in such a way that repository administrators can easily refer to them, if they are supposed to. |
That would certainly help @tt4g! But even then I think we'd need more. Because what can you actually do when the builds in your project don't match up? You'd need multiple builds of every single library. And the matrix of ABI-sensitive build options that would drive the list of builds could be large, irregular, and variable. The only way out that I see is to "go Gentoo" and just recompile everything every time. |
@jtv What I wanted to convey was "I think repository administrators should also provide tips on how to avoid problems like this one, since the library's efforts alone are limited". Not all users who retrieve libraries from repositories are familiar with building C++, so I feel a little bad asking them to build libraries they are unfamiliar with themselves to isolate the cause. |
Good point @tt4g. Makes me wonder what we could do to make this easier on people. ISTR CMake and |
@jtv As far as I know, the most famous way to check build options is |
Hello there! I have got some linking error:
/usr/bin/ld: /tmp/ccadqyKa.o: in function `pqxx::internal::(anonymous namespace)::throw_for_encoding_error(char const*, char const*, unsigned long, unsigned long)': db.cpp:(.text+0x1dc): undefined reference to `pqxx::argument_error::argument_error(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::source_location)' /usr/bin/ld: /tmp/ccpFKSJv.o: in function `pqxx::internal::(anonymous namespace)::throw_for_encoding_error(char const*, char const*, unsigned long, unsigned long)': echo.cpp:(.text+0x1dc): undefined reference to `pqxx::argument_error::argument_error(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::source_location)' /usr/bin/ld: /tmp/ccJw3CDF.o: in function `pqxx::internal::(anonymous namespace)::throw_for_encoding_error(char const*, char const*, unsigned long, unsigned long)': main.cpp:(.text+0x1dc): undefined reference to `pqxx::argument_error::argument_error(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::source_location)' collect2: error: ld returned 1 exit status
As I see my source doesn't matter. It comes from the header <pqxx/pqxx>
Also both variants give the same error:
-lpqxx -lpq
/usr/local/lib/libpqxx.a -lpq
g++ (Debian 13.2.0-1) 13.2.0
psql (PostgreSQL) 15.4 (Debian 15.4-1)
Any advice please?
The text was updated successfully, but these errors were encountered: