jtv / libpqxx

The official C++ client API for PostgreSQL.
http://pqxx.org/libpqxx/
BSD 3-Clause "New" or "Revised" License
1k stars 238 forks source link

problem of installing Windows #306

Closed chenqingguo closed 4 years ago

chenqingguo commented 4 years ago

I install x64 libpq then I build libpqxx using cmake and visual studio 2017. I got this error MSB4126 Debug |x64 is invalid. I need to build x64 libpqxx. How to do? Thanks,chenqingguo.

tt4g commented 4 years ago

What command did you run?

I can build with the following command on x64 Native Tools Command Prompt for VS 2019:

mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Debug -G "Visual Studio 16 2019" -A x64 -DPostgreSQL_LIBRARY="<PATH_TO_POSTGRES>/lib/libpq.lib" -DPostgreSQL_INCLUDE_DIR="<PATH_TO_POSTGRES>\include" -DPostgreSQL_TYPE_INCLUDE_DIR="<PATH_TO_POSTGRES>\include"
cmake --build . --config Debug --target -j 8
tt4g commented 4 years ago

NOTE -A option is important. When this option is not specified, even if you execute CMake on 64bit OS, the generated project file is for 32bit OS.

Visual Studio 15 2017 — CMake 3.17.1 Documentation:

For each toolset that comes with this version of Visual Studio, there are variants that are themselves compiled for 32-bit (x86) and 64-bit (x64) hosts (independent of the architecture they target). By default this generator uses the 32-bit variant even on a 64-bit host. One may explicitly request use of either the 32-bit or 64-bit host tools by adding either host=x86 or host=x64 to the toolset specification. See the CMAKE_GENERATOR_TOOLSET variable for details.

chenqingguo commented 4 years ago

Well. Here is my command mkdir build cd build cmake .. cmake—build. —target INSTALL it works after add -A x64. Do I need to copy the include and lib to my program? I thought make installand add find_packagein my cmakelists is all what should do. Thanks

tt4g commented 4 years ago

Do I need to copy the include and lib to my program?

No, specify lib and include only if CMake cannot find the PostgreSQL library. I have specified it because my machine has a custom install of libpq.

GordonLElliott commented 4 years ago

I also had (and fixed) issues with Visual Studio 2019 (version 16). (And thanks for some of the comments on istall, I will integrate those into my process.)

I had bugs appear. I just installed the new version of VS 2019 in last few days, so I suppose the latest. Compiling for 64 bit (-A flag) and 2019, etc., and test in debug mode. Neither the test suite, nor the actual library, would run correctly until I made 2 modifications:

Here is what I did to fix:

IN strconv.cxx, starting line 478:

case 'N':
case 'n':
    // Accept "NaN," "nan," etc.
    ok =    // [GLE] Note text[3] does not exist and triggers failure.
      (text.length() == 3 and (text[1] == 'A' or text[1] == 'a') and
       (text[2] == 'N' or text[2] == 'n') /*and (text[3] == '\0')*/);

IN test_main.hxx, starting line 134. Note that test_main.hxx does not appear in the project directory, is one directory level above runner.cxx in either of the 'runner' or 'unit_runner' sub-projects. It is included in the respective runner.cxx file, and I followed the link. This is a common file, and only needs to be changed once for both sub-projects:

// [GLE] add argc and make test_name null without an an argv[1].
int main(int argc, char const *argv[])
{
  char const *const test_name = argc>1? argv[1]: NULL;

THESE ARE THE ONLY MODIFICATIONS that I needed to successfully run the entire testing suite for pqxx with Visual Studio 2019.

jtv commented 4 years ago

For the record, @GordonLElliott filed these problems as #307, and the fixes have been merged into master and the 7.1 working branch (see #274).

jtv commented 4 years ago

@chenqingguo is your problem solved now?

jtv commented 4 years ago

I have just released 7.0.6, which contains the fixes mentioned here.

GordonLElliott commented 4 years ago

<...>

I can build with the following command on x64 Native Tools Command Prompt for VS 2019:

mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Debug -G "Visual Studio 16 2019" -A x64 -DPostgreSQL_LIBRARY="<PATH_TO_POSTGRES>/lib/libpq.lib" -DPostgreSQL_INCLUDE_DIR="<PATH_TO_POSTGRES>\include" -DPostgreSQL_TYPE_INCLUDE_DIR="<PATH_TO_POSTGRES>\include"
cmake --build . --config Debug --target -j 8

For my purposes, I coplied the cmake commands into a batch file (which also set up the MS variables). This was very helpful--I was completely new to Cmake. (Started with an old version installed and 3 versions of PostgreSQL including an X86, so Cmake found every possible way to mess up that it could find. The above would force correct versions of everything, I think, or at least fail so I knew what to fix. Especially thanks for this and all the othr work--and consider more detail in the notes on build for Microsoft. (Especially that second line using cmake --build. The original notes suggested some sort of 'make' which doesn't even exist on today's Microsoft. My version found a 16 bit copy somehow!!!)

OH--then after that of course cmake supplies a native Visual Studio 2019 solution file. The user can also directly open that and configure for debug and release there. I personally configured for Unicode characer set, which worked fine--I didn't find yet how to integrate that request into the cmake build. User's may not realize that the solution file is built.

I will comment that finding the final library in a subdirectory of 'src' is weird (that is where it goes on my build). I would prefer it went in a 'lib' directory at same level not inside of 'src'.

tt4g commented 4 years ago

I will comment that finding the final library in a subdirectory of 'src' is weird (that is where it goes on my build). I would prefer it went in a 'lib' directory at same level not inside of 'src'.

@GordonLElliott In the src directory are build artifacts. Just as Visual Studio outputs default artifacts to bin\Debug, placing build artifacts in the lib directory is considered another task.

For CMake, moving from the src directory to the lib directory is done when you run the install target generated by CMake: https://cmake.org/cmake/help/latest/manual/cmake.1.html#install-a-project

jtv commented 4 years ago

Thanks both, I think I have some work to do on the build docs. I'm still not particularly familiar with CMake myself, so I just learned a few things I didn't know!

joeyave commented 4 years ago

I have built pqxx for 64 win. Now when I include it to the project, I have this error:

pqxx.lib(connection.cxx.obj) : error LNK2019: unresolved external symbol __imp_WSAPoll referenced in function "void __cdecl `anonymous namespace'::wait_fd(int,bool,struct timeval *)" (?wait_fd@?A0x909bfe52@@YAXH_NPEAUtimeval@@@Z) project6_part2.exe : fatal error LNK1120: 1 unresolved externals

jtv commented 4 years ago

Sounds like you need to link to the socket library... Is it called ws2_32 on Windows? It may take more.

jtv commented 4 years ago

In the configure build, I link with ws2_32, wsock32, and/or winsock, as available, in that order. The CMake build links only to those first two — I think the last one may be an older thing. So perhaps your application needs to link with ws2_32 and wsock32 as well.

joeyave commented 4 years ago

wsock32

it helped. Thank you. But now I've got abort message. My code:

#include <iostream>
#include <pqxx/pqxx>

int main() {

    pqxx::connection C;

    return 0;
}
tt4g commented 4 years ago

@joeyave Maybe throw exception from pqxx::connection constructor. You should add try-catch statement.

chenqingguo commented 4 years ago

@jtv yes, buildiing succeed, but I think make install in windows is invalid. I'm learning how to use pqxx, I want to insert 'std::vector<>' into array real[] of pg database. Here is my test code,

******
pqxx::stream_to inserter(transaction,"test");
for(int i=1; i<99;i++)
{
tmpData tmpdata;
tmpdata.id=to_string(i);
tmpdata.feature=vector<float>(0.1*i,500);
inserter<<std::make_tuple(tmpdata.id,tmpdata.feature);
}
inserter.complete();
transaction.commit();

the result of id in database is right, but the array is incorret. The array is {} in my table--test. Is there an approprite way to insert vector using pqxx?

tt4g commented 4 years ago

@chenqingguo

make install in windows is invalid.

Since CMake 3.15, use cmake --install <dir> instead: https://cmake.org/cmake/help/latest/manual/cmake.1.html#install-a-project Another way is to use cmake --build . --target install: https://stackoverflow.com/questions/34040522/is-there-a-cmake-install-switch/34040747

jtv commented 4 years ago

Good point. When you construct a connection, you connect to the database. That could be failing because the database is not running, or because it's on a different port, or because your default user does not exist, or you need to provide a password, or because the database does not exist...

Catch the exception and print its what() message.

GordonLElliott commented 4 years ago

OH--H****. Fail is I'm running install without admin privilages--will try that next!!!!!!!!!!!!!!!!!!!!!!!!!

The cmake --install appears to fail, and also triggering the "INSTALL" in the VS 2019 IDE also fails. Just references the post build batch as whole, and error 1, no detailed explanation.

FOR ALL SHOWING a method to do install -- please tell if you have actually tested this method successfully! (As opposed to just finding cmake instruction; which is tremendously valuable of course because it is the only way we will figure it out.)

I saw install location variables somewhere in the original materials. I syspect that something is wrong in all that setup so that the GUI based install does not work out.

By the way, the "PACKAGE" utility in the GUI successfully creates a gzip file--I have no idea yet what it does.

HEY! The "PACKAGE" builds a gzip of a the install needed. But this step executes in my VS gui, while the "INSTALL" step fails. I can extract the gzip that it creates as a binary install....... I will try that and report. At least this shows that the essence of "INSTALL" is already working, just some specific failure in the project as automatically constructed.

This gzip contains the pqxx library, and clean copies of the include directory!

GordonLElliott commented 4 years ago

NOTE: See messages below--successfully installed (need to be administrator), but it put in the Program files (X86) directory. Otherwise very nice. -- IN CASE these notes were useful....

I am still trying to do an "install" (don't know how yet) on X64 build, so the copies needed for regular usage are in the weird locations (as mentioned above).

But the build package also includes examples in the form of the tests (runner, unit_runner) which demonstrate linking for X64 in the weird locations of the build. Can use that until get an install to a sensible location for all.

Specifically for person with linking in x64, here are my libraries (obviously change to correct locations on your system):

In properties--linker--additional dependencies:

C:\pqxx_7\build64\src\Debug\pqxx.lib;C:\Program Files\PostgreSQL\12\lib\libpq.lib;wsock32.lib; .....

where ..... is the original on that line. Obviously I built at top level C drive in my case so I could use for the time being, you can figure out what I did. (Someone comment on missing socket library???) This compiles. I have not tested yet my dummy application which does not have connect string so I will need to set up environment variables, which can be done in the VS debugger by the way for testing.

THERE SHOULD be better practice than this method, for example set library path separately and only library names in the list of libraries. (That way only fix the paths when change compiler setup, but it is the sema library wherever it lands.) This example is just to get the list which then does work.

(Also here is what I set to refer to the not-yet-installed library include files, once again copying from the test cases): IN properties--C/C++--general--Additional Include Directories (here the full line)

C:\Program Files\PostgreSQL\12\include;C:\Program Files\PostgreSQL\12\include\server;C:\pqxx_7\build64\include;C:\pqxx_7\libpqxx-master\include;%(AdditionalIncludeDirectories)
GordonLElliott commented 4 years ago

And I need to configure my build for Unicode, not multi-byte character set. (Did I already mention?)

I have successfully done that manually. First cmake to build the VS solution. Then open with VS and change the pqxx, runner, and unit_runner properties to use Unicode. This works successfully and the test suite works completely. However it is a manual intervention and as yet not "installed" (since I don't know yet how to do that and the install job in the VS solution fails). All references I have found on the Internet suggest this must be burried in the cmake setup files, and if done then possibly give a define option to trigger automatically. For now even if I had an install step that worked, I would have to stop for the manual intervention to set Unicode character set, so I could not automate as a continuous build--install process with a single batch file either.

GordonLElliott commented 4 years ago

Everyone ignore my statement that INSTALL project does not work.

It works (sort of) if you run with administrative permissions. Either in a batch file (I presume) with admin privilages, or in separate step. I will describe how to run INSTALL from VS2019 IDE (presumably works others).

The trick is that even if you are logged in as admin, the VS2019 IDE does not run as administrator. That makes sense, you don't want compiling events (which may have been written by others) to trigger operating system changes--that could introduce viruses etc when unscrupulous persons are involved.

So after build steps have worked (and in my case use the VS IDE to change to Unicode character set and rebuild, or any other changes you require). THEN exit the VS IDE (if open).

Then go to the start menu and find your VS IDE, and right click and follow more options to "run as administrator".

DO NOT do any other tasks as admin -- I recommend -- just the install.

Right click on the INSTALL project, and build.

The problem:

Even though I built as X64, it installed the library and include files in the C:\Program Files (x86)\libpqxx directory for Win32 programs.

OTHER than that--this is a very nice install, clean of almost everything supurflous.

The methods using a command line (say in batch file) to trigger this may have options to override. Or one could take the post build event, make a batch file, and edit to include additional directive to select the correct location--I have not figured that out yet.

ALSO note that the PACKAGE project builds a gzip of the same files. Then you could manually or by batch file (as administrator) expand the gzip into the correct location, either program files (and not the (x86) directory) or if you chose a different install location. Once again someone may figur out how to set this into the INSTALL project--probably a -D or something.

I will be testing usage of this and report....

tt4g commented 4 years ago

@GordonLElliott You can change install location with --prefix option. e.g: cmake --install <dir>--prefix <install-prefix> See cmake --install document: https://cmake.org/cmake/help/latest/manual/cmake.1.html#install-a-project

Another way: cmake -DCMAKE_INSTALL_PREFIX=<instal-prefix>

https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html#variable:CMAKE_INSTALL_PREFIX

CMake is a cross-platform tool. It is the user's responsibility to perform the installation with administrator privileges, when writing during installation requires administrator privileges. Due to security issues, CMake functionality cannot ignore permissions. This is also true for Linux and MacOS.

GordonLElliott commented 4 years ago

Reporting results latest version (7.0.6)

I just downloaded the latest, applied my (slightly updated) batch file, and used the INSTALL project (as described above using administrator priviledges). Then tested the library with a modified Employee database example program.

Another way: cmake -DCMAKE_INSTALL_PREFIX=<instal-prefix>

I added to my original build batch file the suggested install prefix (thanks tt4g) which worked perfectly. I used that method rather than a cmake --install method since I wanted the built up project (VS 2019 solution) to have the target within itself, so that could be run from the IDE. This worked perfectly, and the INSTALL project installed in the desired directory.

Furthermore I tested with both null and empty string ('') data in database for conversion to both int and float types, and found that the throw reports were completely consistent and no debugging traps occured. So all the new changes work.

Here is my batch file to build (but not install) the project from just raw data:

rem GLE build pqxx7...
rem
rem   ** First delete all subdirectories (namely build and any old libpqxx-master)
rem      Copy new clean copy of libpqxx-master directory in to this directory. Cmake line
rem      must properly refer to this location (Files should be just under libpqxx-master)  **
rem
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\Build\vcvarsall.bat" x64
md build64
cd build64
cmake ../libpqxx-master -DCMAKE_BUILD_TYPE=Debug -G "Visual Studio 16 2019" -A x64 -DPostgreSQL_LIBRARY="C:\Program Files\PostgreSQL\12/lib/libpq.lib" -DPostgreSQL_INCLUDE_DIR="C:\Program Files\PostgreSQL\12\include" -DPostgreSQL_TYPE_INCLUDE_DIR="C:\Program Files\PostgreSQL\12\include" -DCMAKE_INSTALL_PREFIX="C:\pqxx_7.0.6_new"
if %errorlevel% neq 0 goto :error
cmake --build . --config Debug --target -j 8
if %errorlevel% neq 0 goto :error

goto :OK
:error
echo Failed with error #%errorlevel%.
pause
exit /b %errorlevel%
:OK
pause

I'm sure there are better ways to do this, but it demonstrates all the features. Of course change all directories to be correct for your machine. I just click on the batch file in a directory with only the batch file and latest libpqxx-master directory, and it builds the Solution for Visual Studio 2019. Then building the INSTALL project (with IDE opened as administrator) installs correctly.

Thanks again to everyone who contributed ideas, too numerous to name. I started with a cmake that referred to the wrong version of PostgreSQL, built the wrong kind of program using the wrong version of Visual Studio and put it in the wrong place. (And crashed in the debugger without running the verification testing.) Now (with extra thanks to jtv) I have a clean install that passes all test!

jtv commented 4 years ago

Thanks for figuring this all out and documenting it!

GordonLElliott commented 4 years ago

I simplified the batch file, removing some flags that were not in the documentation or help, or otherwise the system complained about and didn't work.

rem Build pqxx from CMake files. (Place libpqxx-master directory with files in parallel with batch file)
rem Output will be placed in directory build64. Run Visual Studio as Administrator to build INSTALL as Release.
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\Build\vcvarsall.bat" x64
if %errorlevel% neq 0 goto :error
cmake -S libpqxx-master -B build64 -G "Visual Studio 16 2019" -A x64 -DPostgreSQL_LIBRARY="C:\Program Files\PostgreSQL\12/lib/libpq.lib" -DPostgreSQL_INCLUDE_DIR="C:\Program Files\PostgreSQL\12\include" -DPostgreSQL_TYPE_INCLUDE_DIR="C:\Program Files\PostgreSQL\12\include" -DCMAKE_INSTALL_PREFIX="C:\Program Files\libpqxx"
if %errorlevel% neq 0 goto :error
rem change Release to Debug to pre-build a debug copy. IDE opens as Debug no matter what.
cmake --build build64 --config Release
if %errorlevel% neq 0 goto :error
pause
goto :EOF
:error
echo Failed with error #%errorlevel%.
pause
exit /b %errorlevel%

This will build a Release -- or change the one occurrence of "Release" to "Debug" will build a debug copy. Note that the libpqxx.sln solution will be set for "Debug" no matter what (we have not found a switch that changed the setting on the solution, the build config only afects which was pre-compiled in the batch file not the solution itself.

Then as before use the IDE run as Administrator to actually install, or possibly set up a batch file to trigger the INSTALL project in the solution. The INSTALL project will be configured to install in the C:\Program Files\libpqxx directory.

New Install Problem:

Now the problem: The install for Debug and Release put the pqxx.lib file in the same location. Yes, I could make completely different projects for Debug and for Release, with complete duplicate copies of the include files and documentation.

Furthermore the install does not copy the pqxx.pdb file along with the pqxx.lib in the Debug install. So if you were to recompile the Debug pqxx project without installing, then you can't link to the debug .lib file any more because it actually referes back to the .pdb file in your compile directory. (I tested this and it failed--but if I install the .pdb with the .lib then it does not fail just by rebuilding the pqxx project.)

By the way, the source files become an important part of the debug installation, where they were compiled. If you step into a user program compiled against the debug pqxx.lib you can step into the source debugging with the files in their location where they were compiled.

See: https://docs.microsoft.com/en-us/visualstudio/debugger/specify-symbol-dot-pdb-and-source-files-in-the-visual-studio-debugger?view=vs-2019

https://www.wintellect.com/pdb-files-what-every-developer-must-know/

Method I would recommend is either maintain separate locations for release and debug install, or my manual method: I copy the generated pqxx.lib and pqxx.pdb into a lib\Debug directory alongside of the release lib\pqxx.lib file. (Could make a batch file for that install approach I suppose--still a missing aspect of the install methodology.) The install method has already done the heavy lifting of separating out the include, document, and possibly release library, so this is a minor step.

tt4g commented 4 years ago

@GordonLElliott I think only some developers install debug-built libraries. They can freely change the installation location with CMAKE_INSTALL_PREFIX.

GordonLElliott commented 4 years ago

@GordonLElliott I think only some developers install debug-built libraries. They can freely change the installation location with CMAKE_INSTALL_PREFIX.

As I mentioned, that results in duplicate include and document directories as well, and does not resolve the lack of the pqxx.pdb in the install directory.

The IDE build produces a nice directory (though weird location) build64\src\Debug . I suppose I could make a batch file to copy the Debug directory to the install lib diretory, after building both Debug and Release configurations and installing the Relase first to set up the entire structure and heavly lifting.

tt4g commented 4 years ago

The IDE build produces a nice directory (though weird location) build64\src\Debug . I suppose I could make a batch file to copy the Debug directory to the install lib diretory, after building both Debug and Release configurations and installing the Relase first to set up the entire structure and heavly lifting.

The build directories are separated because you are using Visual Studio as a generator with CMake. MinGW and gcc should not create Debug or Release directories. As a result, batch files will not work cross-platform.

CMake scripts are currently maintained by contributors. After adding the batch file, someone must maintain it. Furthermore, CMake also has RelWithDebInfo and MinSizeRel as build type. Don't forget these things for full support.

I can't decide whether or not to support it, as all support adds work to the project.

GordonLElliott commented 4 years ago

That .pdb problem is important, if we have a separate install method (separate from the build, I mean). And the separate install method is important to separate out the proper include files from the larger source code project.

I'm not sure why so many build types are needed (just because CMake supports them). I definitely do in some cases of embedded systems I work on, I really needed a debug of release compiled code because it wouldn't fit in a tiny chip. But on these kind of projects, why more than debug and release? Even typical Microsoft IDE created projects only default with those two options. Oh, yes I have had failures that only occurred in relase compile and wanted to debug..... (but rare). (These kinds of failures were actually the kind that the modern complier caught in the original code here before the last few fixes, like referencing non-existent memory locations that changed between debug and release. Now debug versions trap these more often.)

If we can only have a way to distinguish the library locations for Release and Debug, and include the pqxx.pdb file in Debug, that is all the distinguishing I think is needed. Already more than I expected.

I only meant the batch files as examples--one would never release them, just possibly in documentation as examples specific to Windows. Users would need to configure the options themselves anyway and they are mostly just setting parameters one would have a pain doing for CMake if not in a script of some sort. And I am desperate to get this to work, have multiple projects to convert to pqxx 7.

By the way, I understand some only use release, but then why are they compiling in the first place? If they are doing more than recompiling someone else's project for release, then they are debugging!

tt4g commented 4 years ago

If we can only have a way to distinguish the library locations for Release and Debug, and include the pqxx.pdb file in Debug, that is all the distinguishing I think is needed. Already more than I expected.

Specify the absolute path to the location of the .pdb file in the generated .lib. Therefore, it does not make sense to modify the .pdb file generated during installation. Because .lib and .dll cannot find the relocated .pdb.

If you absolutely want to place .pdb in the installation destination, specify CMake variable PDB_OUTPUT_DIRECTORY as the installation destination: PDB_OUTPUT_DIRECTORY — CMake 3.17.1 Documentation Since the .pdb file is created at the destination specified in this variable, the path of the .pdb file in .lib will also be the specified path.

CMake installs include files and release libraries needed by many users by default. Due to the large size of pdb files and debug libraries, many users do not need to install them. I think it makes sense to customize the installation of it with CMake arguments.

chenqingguo commented 4 years ago

@jtv

Catch the exception and print its what() message.

I do have catch, It's just a part of code not all. Connection and database are ok, and inserting string is ok but not vector. I found a array test, and solve my problem.

GordonLElliott commented 4 years ago

Ah..., investigating. But:

https://cmake.org/cmake/help/latest/prop_tgt/PDB_OUTPUT_DIRECTORY.html

But in the documentation on that page:

Note This property does not apply to STATIC library targets because no linker is invoked to produce them so they have no linker-generated .pdb file containing debug symbols.

This is flat out wrong! There is a pqxx.pdb alongside the pqxx.lib in the \src\Debug directory when doing a Debug build on VS 2019.

I'll investigate if there is also a way to specify the .lib location, and use only for the debug build. Actually try the PDB_OUTPUT_DIRECTORY first and see what it does.

PS I don't understand "Therefore, it does not make sense to modify the .pdb file generated during installation." I just want that .pdb file placed along side the .lib in the install directory (distinct of course from the Release pqxx.lib). The present Debug INSTALL does not put a copy of the pqxx.pdb in the install directory at all!

OK--I take back some comments, I'm not sure that PDB_OUTPUT_DIRECTORY is relevant. Of course the notion of where it puts the ".pdb" is what I am after--but where it puts the .pdb on the INSTALL step, not the build step. Since the PDB_OUTPUT_DIRECTORY flag is changing the input to the linker, the documentation may be right in the sense that placing that flag value in a linker is not useful and will not work here.

HAVE TRIED many variations, nothing works so far...

GordonLElliott commented 4 years ago

I don't understand the src/CMakeLists.txt . I even regenerated it from the template and it still works, but:

The only location I see installing files is in the macro, that having a condition:

    if(NOT name STREQUAL output_name AND NOT CMAKE_HOST_WIN32)

If it only installs files when NOT on Windows, where are the rules to set up the install project?

GordonLElliott commented 4 years ago

A working Release/Debug install with VS2019

I've run out of time to try to figure out internal options. The command line options in this batch file have pretty much been tested to all work and are documented. (Other ideas have not worked so far.)

This batch file uses the CMake built INSTALL program of Visual Studio solution to install both the Release and Debug projects.

It uses normal install process for Release, then circumvents the CMake process to copy the Debug result into the target directory, in the lib/Debug subdirectory -- complete with both pqxx.lib and pqxx.pdb. You have to maintain the original compile directory to enable debugging into pqxx functions--which works in my case. (There are many tutorials on placing source code and Microsoft .pdb files for enterprese level debugging--this is just simple set up a project source directory of your own here and place the batch file and source files directory there..)

Updated so you can set MultiByte (default) or Unicode character set. (I need Unicode, while build defaults to MultiByte in the IDE.)

Batch build file:

REM Build pqxx from CMake files. (Place libpqxx-master directory with files in
REM parallel with batch file.) Intermediate files will be placed in directory 
REM build64. Installs both Release and Debug to INSTALL_DIRECTORY location.
REM Requires administrator privileges if INSTALL_DIRECTORY is Program Files.

REM *** Builds both Release and Debug. Installs Release using INSTALL in IDE 
REM *** from CMake. THEN circumvents Cmake process by copying the Debug output
REM *** to the install target lib directory, lib\Debug, with the pqxx.pdb file.
REM ***
REM ***     *** SET YOUR INSTALL DIRECTORY Here     ***
setlocal
SET INSTALL_DIRECTORY="C:\pqxx_7.0.6"

REM Set cores to number of CPU cores on your machine, or 1 to disable. Set 8 
REM cores only shaves 1.5 minutes out of 9-10 minute compile time on an older 
REM computer, probably because multi-tasking gets confused and compiles some 
REM files multiple times with more than one cores.
SET CORES=1

REM CHARSET must be exactly "Unicode" or "MultiByte" or else will not work 
REM correctly:

REM SET CHARSET="Unicode"
SET CHARSET="MultiByte"

REM Note that the VS IDE solution is set for MultiByte, regardless of this 
REM setting. If you use Unicode and intend to comple in the IDE, you must 
REM change pqxx, runner, and unit_runner projects to Unicode character set.

echo Start %CHARSET% build, cores: %CORES% >> timer.txt
echo Start build: %time% >> timer.txt

call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\Build\vcvarsall.bat" x64
if %errorlevel% neq 0 goto :error
cmake --verbose -S libpqxx-master -B build64 -G "Visual Studio 16 2019" -A x64 -DPostgreSQL_LIBRARY="C:\Program Files\PostgreSQL\12/lib/libpq.lib" -DPostgreSQL_INCLUDE_DIR="C:\Program Files\PostgreSQL\12\include" -DPostgreSQL_TYPE_INCLUDE_DIR="C:\Program Files\PostgreSQL\12\include" -DCMAKE_INSTALL_PREFIX="%INSTALL_DIRECTORY%"
if %errorlevel% neq 0 goto :error
REM change Release to Debug to pre-build a debug copy. IDE opens as Debug no 
REM matter what.

REM Usage: cmake --build <dir> [options] [-- [native-options]]
REM Options:
REM   <dir>          = Project binary directory to be built.
REM   --parallel [<jobs>], -j [<jobs>]
REM                  = Build in parallel using the given number of jobs.
REM                    If <jobs> is omitted the native build tool's
REM                    default number is used.
REM                    The CMAKE_BUILD_PARALLEL_LEVEL environment variable
REM                    specifies a default parallel level when this option
REM                    is not given.
REM   --target <tgt>..., -t <tgt>...
REM                  = Build <tgt> instead of default targets.
REM   --config <cfg> = For multi-configuration tools, choose <cfg>.
REM   --clean-first  = Build target 'clean' first, then build.
REM                    (To clean only, use --target 'clean'.)
REM   --verbose, -v  = Enable verbose output - if supported - including
REM                    the build commands to be executed.
REM   --             = Pass remaining options to the native tool.
REM (On pass options):
REM https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-command-line-reference?view=vs-2019   

REM NOTE that -j parametr more than 1 allows for faster compiling, but 
REM     may re-compile a file more than once. Set no higher than number of 
REM cores on your computer.
REM Note that addition of -- /p:CharacterSet=Unicode
REM does change from _MBCS to UNICODE, which can be observed in the
REM CL command line used (as shown by --verbose) in compile,
REM but does not change the MS solution file in the IDE.

cmake --build build64 --verbose --clean-first --config Debug   -j %CORES% -- /property:CharacterSet=%CHARSET%
if %errorlevel% neq 0 goto :error

cmake --build build64 --verbose --clean-first --config Release -j %CORES% -- /property:CharacterSet=%CHARSET%
if %errorlevel% neq 0 goto :error

REM ********************************************************************
REM **** Below this point, requires administrator privileges,   ****
REM **** if that is required by the INSTALL_DIRECTORY. If so,   ****
REM **** recommend breaking into separate batch files so that   ****
REM **** build is not done with administrator privileges.       ****
REM ********************************************************************

REM Install the Release copy in the normal manner. This does the
REM heavy lifting of include and doc directories as well as lib with 
REM Release library, also in the normal manner.
cmake --build build64 --target INSTALL --config Release
if %errorlevel% neq 0 goto :error

REM Here copy the Debug directory   (Return 0 up to date, 1 copied OK)
robocopy "build64\src\Debug" "%INSTALL_DIRECTORY%\lib\Debug" /MIR /E /R:0 /DCOPY:T /Z
if %errorlevel% gtr 1 goto :error

REM ********************************************************************
REM ****          Error and exit processing                         ****
REM ********************************************************************

REM You can double click this file in the top level directory for the project,
REM and pauses so the command window does not go away before you see the 
REM results. The timer.txt file shows start and end times of the batch runs.
echo End   build: %time% ***>> timer.txt
pause
goto :EOF
:error
echo Failed with error #%errorlevel%.
pause
exit /b %errorlevel%

This has been tested wtih a modified Employee example program set to the library and include as installed, compiled in both Debug and Release configurations. As before seems to pass all tests, and debugging can step right into the pqxx library source in your original build location.

Copying (or not copying) the pqxx.pdb file is a complex subject, as is where to keep the original source which must be maintained if one is to debug into that source. See:

See: https://docs.microsoft.com/en-us/visualstudio/debugger/specify-symbol-dot-pdb-and-source-files-in-the-visual-studio-debugger?view=vs-2019

https://www.wintellect.com/pdb-files-what-every-developer-must-know/

Other options with an easy change of the batch file would be to copy only the library to Debug subdirectory, or copy the library with a 'd' suffix, etc. (If Cmake were easier to navigate and had better support for Microsoft these cases would all be easy to make as command line options--they are all common methods used in the Microsoft world. I understand that Cmake is supporting an amazing array of target systems--this above is a quick and dirty method to get me going!)

tt4g commented 4 years ago

PS I don't understand "Therefore, it does not make sense to modify the .pdb file generated during installation.

The debugger looks for and loads .pbd from the same path where the .pdb file was generated and the same directory as the .exe when loading the .pdb. This means that once a generated .pdb file is installed in the same directory as.lib, it doesn't make sense to most users as it won't load during debugging.

debugging - C++ PDB Symbols not loaded from same directory - Stack Overflow

GordonLElliott commented 4 years ago

New C++ project settings to use (above) installed pqxx library

These settings assume the directory I used in the previous post, of pqxx.7.0.6, not Program Files. (You can edit to your preferences of course). I did that to keep my build simple without admin priviledges, but of course you will want to set your own policies.

Set for all configurations.

Properties--Configuration Properties--VC++ Directories--Library Directories:

C:\pqxx_7.0.6\lib;C:\Program Files\PostgreSQL\12\lib\;$(VC_LibraryPath_x64);  ....

The .... is whatever your project default generated.

Then ... C/C++--General--Additional Include Directories:

C:\pqxx_7.0.6\include;C:\Program Files\PostgreSQL\12\include;C:\Program Files\PostgreSQL\12\include\server

(Apparently was blank as default??)

I am not sure this is best practice... May want to put these in Properties--Configuration Properties--VC++ Directories--Include Directories, so as to be consistent with the other directory changes. (PS: Tested with prepending to VC++ Directories--Include Directories and worked fine, I think this is more consistent. I don't know the distinction.)

Then ...C/C++--Language--C++ Language Standard:

ISO C++17 Standard (/std:c++17)

Then Release: ...--Linker--Input--Additional Dependencies:

pqxx.lib;libpq.lib;wsock32.lib;ws2_32.lib; ...

(I'm pretty sure this agrees with the dcumentation to this point.) ... is default from new project. I did the configuration specific because often the library names are different on debug and release.

Then same for the Debug configuraion:

Debug\pqxx.lib;libpq.lib;wsock32.lib;ws2_32.lib; ....

Thus differentiating the debug library (in this case into a subdirectory--other libraries might use a 'd' suffix for debugging, etc, in this field.

Unless I am mistaken, that is all the modifications from default new VS2019 project setup as Console app that I needed.

GordonLElliott commented 4 years ago

The debugger looks for and loads .pbd from the same path where the .pdb file was generated and the same directory as the .exe when loading the .pdb. This means that once a generated .pdb file is installed in the same directory as.lib, it doesn't make sense to most users as it won't load during debugging.

See a previous post I made. I am sure there are different ways to do this. In your linked website, they said they "moved" the PDB, and I don't know if they really meant "move" or just "copy". Moving would be a weird thing to do, IMO.

See: https://docs.microsoft.com/en-us/visualstudio/debugger/specify-symbol-dot-pdb-and-source-files-in-the-visual-studio-debugger?view=vs-2019

https://www.wintellect.com/pdb-files-what-every-developer-must-know/

As per my referenced pages (duplicated here), I tested with and without COPY of the pqxx.pdb to be next to the pqxx.lib in the local install directory. In both case, I could compile and then debug right into the source code in the original compile location.

NOW the difference:

Without the copy of the pqxx.pdb, if I simply rebuilt the source library -- not re-installing the pqxx.lib in the install directory, just recompile the source---:

Then I can no longer link the debug without errors! (Same if the source became temporarily unavailable as on a network drive.)

(I thik there are serious probelms if you change the source and do not install, however, since the line numbers in the PDB file would no longer agree and debugging into pqxx source would get weird!)

But another case is where the source is kept on a removable or network drive. Then one can go off and compile without connection to the network drive (if .pdb file is local) and debugging will only fail when one actually steps to one of the files that are offline.

Without the .pdb in the install--the linker requires the .pdb to be available at the source location at the time of the linking.

Note the 2nd' search location is besid the library (or DLL or EXE) file, the first search is the original. That is why compiling still works with the local copy, but it is not used if the original source is present. THIS IS a complicated subject--and I am sure that there are many cases where one does not want the PDB file to be copied. I do still want a separate copy of the debug library, and prefer not to have a complete separate install of the include and doc to go with that.

jtv commented 4 years ago

What I keep wondering about is: how do people normally do all this with CMake and Visual Studio!?

tt4g commented 4 years ago

@jtv IMO.

Visual Studio IDE should be able to build libpqxx with CMake.

@chenqingguo who opened this issue seems to be unable to resolve the issue in this comment (https://github.com/jtv/libpqxx/issues/306#issuecomment-619465928).

There is a comment that mentions installing the debug symbol file (.pdb) with CMake, As I commented above (https://github.com/jtv/libpqxx/issues/306#issuecomment-619464356), most users don't need it, so I don't think I need support.

GordonLElliott commented 4 years ago

I think chenqingguo figured out his problem, because I learned to do what I did in part from one of his posts.

One thing I realized is that we don't have to find the compiler location--CMake does that! (Especially if you specify the compiler).

Here is much simpler batch file that uses VS 2017 (and tested that it makes a library without complaint):

REM Cmake build of libpqxx for Visual Studio 2017.
REM ***     *** SET YOUR INSTALL DIRECTORY Here     ***
setlocal
SET INSTALL_DIRECTORY="C:\pqxx_7.0.6_VS2017-x64"

REM Remove the Win64 if you want a 32 bit compile: "Visual Studio 15 2017"
cmake --verbose -S libpqxx-master -B buildVS2017-x64 -G "Visual Studio 15 2017 Win64"  -DCMAKE_INSTALL_PREFIX="%INSTALL_DIRECTORY%"
if %errorlevel% neq 0 goto :error

REM change Debug to Release if you don't want a debug library.
cmake --build buildVS2017-x64 --target INSTALL --verbose --config Debug
if %errorlevel% neq 0 goto :error

pause
goto :EOF
:error
echo Failed with error #%errorlevel%.
pause
exit /b %errorlevel%

Comments show how to switch to 32 bit or to Release configuration.

One can put this into a batch file alongside of directory libpqxx-master with all the files just underneath that, and double click the batch file to run it. This creates the working and install directories. (No changing directory.)

tt4g commented 4 years ago

@GordonLElliott See this comment and CMake document

-G "Visual Studio 15 2017 Win64" is old CMake generater name. The recommended platform option is -A since CMake 3.2 and above.

chenqingguo commented 4 years ago

well, I don't think providing a batch file is a good way. Chossing which platform,directory or something else to compile should be done(accroding to user's compiler) in cmaklists. Centos is my product environment, and I focus on how to use API efficiently.

jtv commented 4 years ago

I agree (and I think that everyone here probably agrees) that it'd be best to have a CMakeLists that "just works."

Question is, how do we get there?

tt4g commented 4 years ago

@jtv CMake is similar to the autotools configure script. It is recommended to specify the compiler etc to be used by the argument when executing CMake

The big difference from the configure script is that it generates a build tree other than Makefile according to the CMake generator.

Generates a Makefile or project file that a CMake generator, such as make, Ninja, or Visual Studio, specified by the -G option can perform the build (this feature makes CMake a cross-platform tool).

Unfortunately, as far as I know, the CMake generator cannot changed when CMake is executed and should not be changed in CMakeLists.txt.

the only solution to the first issue mentioned in this issue is for the user to specify a CMake generator with the -G option: https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html

See also: What is a CMake generator? - Stack Overflow

In other words, CMakeLists.txt should work, but it didn't work because the options CMake needed were not passed.

Addition:

the user can change the compiler and compile options, etc. We should check the CMake documentation for how to set up the build tool. I think here is how to change the typical toolset.

For example, the default C++ compiler determines from the CXX environment variable: CXX — CMake 3.17.1 Documentation Specify CMAKE_CXX_COMPILER variable to use a compiler different from CXX environemnt variable (e.g. cmake -DCMAKE_CXX_COMPILER=clang).

GordonLElliott commented 4 years ago

I've been giving batch file lists for a number of reasons. For one they document commands that could be entered by hand--but are a lot of trouble to type out. Also I needed something to use to get the job done the way I wanted for my clients, and the CMake by itself did not work.

I just installed the PostgreSQL version 10 libraries. Now without specifying, it does not use the latest (12.2), but rather chooses the 10 library for use. With all the (complicated) flags I can set. Far too much to type in every time a long command line, using a batch file to do that.

GordonLElliott commented 4 years ago

Question is, how do we get there?

For example who else is more dependent upon Find Postgres than pqxx users? (That is one thing that fails for me when I have more than one install of PostgreSQL. And it is the hardest to repair because it takes at least 3 settings, as far as I can tell. But multiple compile tools is just going to happen and people simply need to tell CMake which one of theirs they want.)

An example of improving CMake (or supporting code) is: https://github.com/pgRouting/pgrouting/issues/301#issuecomment-115701087 Someone tried to solve this problem but it doesn't work and isn't documented or else was not kept.

tt4g commented 4 years ago

Someone tried to solve this problem but it doesn't work and isn't documented or else was not kept.

Users can control find_package(PostgreSQL) result by environment variable <PackageName>_ROOT or CMake variable <PackageName>_ROOT. Look CMake find_package() document:

For example, suppose PostgreSQL is installed in C:\Program Files\PostgreSQL v12. The directory tree has the following structure.

C:\Program Files\PostgreSQL v12
|
|- bin\pqxx.dll
|- lib\pqxx.lib
`- include

If set CMake variable PostgreSQL_ROOT to C:\Program Files\PostgreSQL v12 then find_package(PostgreSQL) search pqxx library and header files in C:\Program Files\PostgreSQL v12. This indicates that the user can specify the version of the library that CMake uses.

If CMake just doesn't find the PostgreSQL library, the user can overwrite the result variable of find_package(PostgreSQL).

When find_package(PostgreSQL) is called, FIndPostgreSQL.cmake is loaded: https://github.com/Kitware/CMake/blob/master/Modules/FindPostgreSQL.cmake By first defining the PostgreSQL_LIBRARY, PostgreSQL_INCLUDE_DIR and PostgreSQL_TYPE_INCLUDE_DIR variables defined in this module, the user can directly specify the PostgreSQL library to link with. e.g. cmake -DPostgreSQL_LIBRARY="<PATH_TO_POSTGRES>/lib/libpq.lib" -DPostgreSQL_INCLUDE_DIR="<PATH_TO_POSTGRES>\include" -DPostgreSQL_TYPE_INCLUDE_DIR="<PATH_TO_POSTGRES>\include"

Controlling the linked libraries that CMake detects requires a lot of variable definitions, so if you're new to CMake you might find it annoying. However, allowing the library search path to be specified directly saves the user in many cases.

Because the installation destination of the library is not decided in Windows OS. Some users have the library installed on the G drive, as the Windows installer provides the option to change the installation location freely. Also, the UNIX system OS has different library installation destinations depending on the distribution. The ability to specify a path to search for the library allows users who have the library installed in a different location than many users to tell CMake that location.

find_package(PostgreSQL) is the de facto standard way to specify the libraries to link with CMake. However, this feature is also a drawback that it is difficult to use unless you are familiar with CMake.

GordonLElliott commented 4 years ago

I ran with -DPostgreSQL_ROOT=... but it said:

CMake Warning (dev) at cmake/config.cmake:19 (find_package):
  Policy CMP0074 is not set: find_package uses <PackageName>_ROOT variables.
  Run "cmake --help-policy CMP0074" for policy details.  Use the cmake_policy
  command to set the policy and suppress this warning.

  CMake variable PostgreSQL_ROOT is set to:

    C:\Program Files\PostgreSQL\12

  For compatibility, CMake is ignoring the variable.

So how to set "policy CMP0074" or ??--I think this can be turned on so it obeys PostgreSQL_ROOT . That would be a lot less typing than 3 variables.