Too much exported symbols for a project compiled with CMake and MinGW - cmake

I'm trying to compile libzint (a barcode generator) for Windows using CMake and MinGW. The aim is to avoid Visual Studio dependencies. All run fine except that the generated .dll file contains too much exported symbols. I should have only ZBarcode_* functions but in fact pretty much anything that is declared as a variable/constant gets exported (and the resulting .dll file have no version information, I think this is strange.)
Here's how I did the job :
git clone from github repository in D:\Projects\Zint
installed cmake in C:\CMake
installed mingw in C:\MinGW
started cmake-gui, browsed to D:\Projects\Zint
clicked "Configure", choosed "MinGW Makefiles" in the list and "specify native compilers", next I specified the full path to c:\mingw\bin\mingw32-gcc.exe (to be sure...)
Clicked "Configure". It succeeded but it added some variables in red because dependencies where not met (PNG and QT but I don't want them and zint is fine without them)
clicked "Configure" again, everything turned white
clicked "Generate"
closed the cmake-gui
started a console prompt
overrode the path variable environment to C:\mingw\bin only
went to "D:\Projects\Zint" and ran "mingw32-make" then "mingw32-make install"
the libzint.dll and zint.exe were deployed to "C:\Program Files\zint-package\bin"
I used Dependency Walker to have a look at the exported functions and saw that in addition to few ZBarcode_* functions there were also around 400 other symbols and given the source code I saw that these symbols are in fact constants, arrays and other internals of libzint.
Do you know how to configure or tweak things to avoid all these exports ?
Many thanks for your help, regards.

Look in the headers for any macros that contain dllexport. If you find one or more, check that it's not malfunctioning.
Another possibility is that all classes are being exported, instead of just the few functions that are necessary.
If you have grep, do grep -nr dllexport *. This will recursively look in all files. For every hit, it will print the file name, line number, and contents of the line.

Related

Cannot get CMake to handle Fortran-90 modules properly

I've had a miserable afternoon trying to add a Fortran-90 module to a large multilanguage library set (mostly C++) built with CMake, and am at the point where I am clearly going in circles. There is an amazing dearth of information online that might help me with this, and the CMake documentation is as inscrutable as always.
The library set is too large to boil down properly (so I've been unable to get a good small reproducer) but the essence of is this. Each library lives in its own directory, with a test directory beneath it. I've added an F90 file containing a module to one of the directories, which I'll call low_library. The contents of this directory are something like:
low_library:
CMakeList.txt
file1.cc
file1.hh
file2.cc
file2.hh
my_module.f90
test:
CMakeList.txt
test1.cc
test2.cc
test3.cc
my_module_test.f90
except many more .cc and .hh files. In the CMakeList.txt file for the library directory, I have instructions that include
add_library(low_library STATIC "")
target_sources(low_library
PUBLIC:
file1.hh
file2.hh
PRIVATE:
file1.cc
file2.cc
)
There's more but it's not obviously relevant.
So the first question is where to put my_module.f90. I want my_module.f90.o to be included in the liblow_library.a file but I need the my_module.mod file to be visible to other libraries I'm building (and to users of the library set). So I add the line
set(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_INSTALL_PREFIX}/fortran_modules)
towards the top of my CMakeList.txt file, add my_module.f90 to the PRIVATE part of the target_sources() PUBLIC list, and ... sigh ... the build system puts the .mod file in the build directory, and not in ${CMAKE_INSTALL_PREFIX}/fortran_modules. The other libraries can't see it and fail to build.
So now I put my_module.f90 in the PUBLIC part of target_sources() and try again. This time the module files goes where I expected it, my test directory can see it and builds successfully, and I'm happy until I move on to building the next library, in directory high_library which depends on low_library. The build comes up with the truly bizarre error:
f951: Fatal Error: Can't rename module file â/scratch/kgbudge/develop/install/fortran_modules/cta_mesh_generator.mod0â to â/scratch/kgbudge/develop/install/fortran_modules/cta_mesh_generator.modâ: No such file or directory
Looking at the rest of the trace, it appears that with my_module.g90 in the public interface of low_library, the build for high_library ignores what's already in my ${CMAKE_INSTALL_PREFIX}/fortran_modules and builds its own copy of the d-mned .mod file in ${CMAKE_INSTALL_PREFIX}/fortran_modules. Which, since we have high-powered build servers and always build in parallel (make -j16 is typical) means a race condition between competing build jobs.
Okay, I know. I needed to include the line
target_include_directories(low_library PUBLIC ${CMAKE_INSTALL_PREFIX}/fortran_modules)
near start of the CMakeLists.txt file for high_library so it knows where to find the modules and wont' try to build its own. Except this doesn't help.
I can find nothing online that gives me any clues what is going on or how to resolve it.
It looks like the problem is that I had my
set(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_INSTALL_PREFIX}/fortran_modules)
only in the libraries that produced or consumed the new modules. But other libraries used the library containing the module and needed to see a copy of the module even though they weren't actually using the module. I think.
Anyway, moving this line into the root CMakeLists.txt allows me to build the whole library successfully. I still seem some warnings:
f951: Warning: Nonexistent include directory â/srcâ [-Wmissing-include-dirs]
but at least it all builds.

Missing dll files error in Objective-C programs

I am a beginner in Objective-C language. I have downloaded and installed GNUstep msys and GNUstep core and installed them in order, as mentioned in the downloads page of GNUstep.
But, I think that the installation isn't correct, because whenever I try to compile an Objective-C source file, it shows fatal error Foundation/Foundation.h file not found. Means, due to some reasons, the path to the header files isn't valid.
Although I am now successfully able to compile the source file with the -I and -L options, I faced another problem. After compilation, when I run the compiled exe file, it shows an error that many dll files are missing, such as objc-4.dll, gnustep-base-1_24.dll to name a few of them. But, I found all of these files present under the /GNUstep/System/Tools folder. When I copied these dll files to my main working (home) directory, it runs successfully without any errors.
Why is this happening? All the tutorials I found on the internet shows very simply the compiling and running of Objective-C programs in Windows without changing so many things. Am I missing something? I have searched many times in StackOverflow and also on the internet, but none of those solved this problem. Please help me and thanks in advance.
P.S. - I have installed GNUstep in the default C:/GNUstep/ folder and included the C:/GNUstep/bin/ and C:/GNUstep/msys/1.0/bin/ folders in the PATH environment variable.
I noticed that there are more than one gcc.exe files present on my system for three different programming language compilers and their parent folders are included in the PATH environment variable. So, the gcc command conflicted with those three executables and therefore, the path to the dll files become invalid.
So, I had to move the GNUstep's bin directory to the top of the PATH environment variable to ensure that the GNUstep's gcc executable is used. And now, everything works like a charm.

Built two different Debian packages for different Build Types using CMake

I have a small CMake project with different Build Types debug and release. I'm also providing a Debian package for this project. Building the Debian Package for release and providing it on my own Debian repository works perfect.
Now I also want to provide another Debian package for debug, due to debugging purposes, with a different package name. For example, my project is called myproject, and the debugging package should be myproject-debug.
I already read documentation about how to solve this in the debian/control file. I want to use Replaces: ... on each package vice versa, so that you can install only one of the both packages at a time. So either myproject or myproject-debug, but not both at the same time, to use the exact same files and filenames but only the binary has more debugging informations and debug prints in the myproject-debug package. Everything else should be the same. Same filename, same paths, etc.
Now the problem is that I don't know how the debian/rules file should look like, to first build the myproject package in a folder and then build the myproject-debug with different CMake options (-DCMAKE_BUILD_TYPE=debug) in a different folder, so the filenames can and should stay the same.
There is this CMake tutorial in the Debian documentation, but this doesn't fit my requirements. Because in this tutorial everything will be built in only one folder, and in this one folder there are different files. Then different .install files will be used to copy the needed files to each package. But since I have the same binary filename for each package myproject and myproject-debug this tutorial does not really fit my needs.
I already have the following lines in my debian/rules file:
override_dh_auto_configure:
dh_auto_configure -- -DCMAKE_BUILD_TYPE=release
But how can I run two different builds with two different build types?
For example, something like this, to split it up:
override_dh_auto_configure_release:
dh_auto_configure -- -DCMAKE_BUILD_TYPE=release
override_dh_auto_configure_debug:
dh_auto_configure -- -DCMAKE_BUILD_TYPE=debug
And run both in different folders so I can add both folders to two different packages.
Or maybe there is even a better solution I cannot imagine yet?

MinGW-w64's ar.exe can't find libraries when trying to build a static library

I've now been trying to get MinGW-w64 to work on my system for several days, mainly because it has a more recent GCC version, but I either set things up wrong or there's some strange problem with MinGW-w64 itself.
I've now downloaded i686-w64-mingw32-gcc-4.7.2-release-win32_rubenvb, unpacked it to C:/Dev/mingw-ruben and added the path C:/Dev/mingw-ruben/bin to the $PATH environment variable.
What I'm trying to build is SFML 2 which comes with a CMake file. Running CMake will work just fine, the compiler gets recognized and passes all test. CMake also finds the ar.exe in the C:/Dev/mingw-ruben/binfolder. After generating the MinGW Makefile I switch to the windows command line and run mingw32-make install.
There's where the problem happens, I get the error:
mingw-ruben\bin\ar.exe: mingw-ruben/lib/libopengl32.a: No such file or directory
Or for the network library
mingw-ruben\bin\ar.exe: mingw-ruben/lib/libws2_32.a: No such file or directory
The error seems quite obvious and on check there really is no libopengl32.a or libws2_32.a in mingw-ruben/lib/, but the files is actually located in C:/Dev/mingw-ruben/i686-w64-mingw32/lib.
Now How can I tell ar/make/cmake to not only search in the mingw-ruben/lib directory but also in the mingw-ruben/i686-w64-mingw32/lib?
Would it be a good idea to copy all the content from the i686-w64-mingw32 subfolder to the mingw-ruben root folder?
As a side note: I can call mingw32-make install again and the procedure will continue but up on trying to link my application against SFML, I run into many unresolved symbol errors for the glXYZ functions from within SFML.
Further information: I'm on Windows 8 x64, but I think that doesn't really matter and yes I've tried MSYS but it doesn't resolve any of my issues.
Am I doing something wrong? Do I have to configure things specially?
January 2015 Edit
Now that SFML 2.2 has been released, this is no longer an issue and you have to link SFML's dependencies yourself when linking static.
January 2014 Edit
As of commit 165f2b1888 and f784fe4c07, which is included in the stable version SFML 2.1, MinGW-w64 compilers are supported.
However while discussing further with different parties it came to light, that the sfml_static_add_libraries marco a rather ugly hack was. In short it unpacked the static dependencies and included their obj files into the SFML library itself. This was most noticeable an issue, when trying to use your own version of GLEW, which failed since SFML was using its internal one already. The issue was brought to the forum and was pushed around for quite a bit, until Laurent finally gave in and went with the proper way of linking dependencies, which means you have to link them now on your own.
As of commit dbf01a775b, which is not included in the stable version of SFML 2.1, one has to link the SFML dependencies in the finally application, when linking statically against SFML.
Original
After some chat on the IRC we've figured it out.
It has nothing to do with MinGW but it's all SFML's fault. To reduce the dependencies list for SFML while linking statically the developer decided to manually extract the symbols from each library (opengl32, ws2_32, ...) which obviously isn't how one does things and violates some ODR rules. The actual error then occurs because the developer assumed that the library will be in the folder mingw/libbut with MinGW w64 it's located in a seperate directory mingw/version/lib and so ar.exe didn't find the library.
Solution
Removing the call to the sfml_static_add_libraries macro and then recompile. Afterwards you'll have to link all the dependencies for static linkages, like it should be.
I think it may be well a problem of the gcc distribution you downloaded.
A bit of light into the problem gives ruben's question here:
https://unix.stackexchange.com/questions/45277/executing-binary-file-file-not-found
that seems to me related to that (although it is about linux and not win)
I was having a similar problem (the name of the missing file was different) few months ago with gcc 4.7.0 linux->win crosscompiler. So until now I lived with the standard ubuntu mingw-w64 package and only yesterday I gave another try to i686-w64-mingw32-gcc-4.7.2-release-linux64_rubenvb.tar.xz and it works without issues in otherwise same environment where the previous version was failing with "..ar.exe: ... no such file". Sometimes I develop also in windows, then I use http://www.mingw.org/ that was for me much easier to setup in Win. It supports only 32bit target but for my project it is sufficient.

What is the correct way to customize the install output directory for each developer in CMake?

I've been working on an old game that I created CMake files for to get rid of a mix of Makefiles and visual studio projects. Everything is working well, but I'm having a hard time figuring out what the correct way to allow the developer to specify where the output files are copied to when install is run.
The issue is there are many DLLs and some custom targets that need their output copied into a directory structure that includes the game data (levels, art, sound, etc) before they can test the code.
My install commands currently uses a variable that I 'SET' at the top level CMakeLists.txt to specify the output directory. I've tried overriding it with -DD3_GAMEDIR on the cmake command line. That variable gets set in the CMakeCache, but the SET command appears to override it still.
Should I be checking the length of the variable before using SET to see if the user specified a value? That seems like a hack to me, but I'm having a hard time finding the correct way to do it.
Thanks!
The install target supports the DESTDIR parameter, so you could do something like:
make install DESTDIR="C:\RootGameDir"
The other option is to only set the variable if it isn't already set (if(myVar)), but I personally prefer the DESTDIR solution.
Here is the anwser, according your cmake version:
SET(CMAKE_VERSION "${CMAKE_CACHE_MAJOR_VERSION}.${CMAKE_CACHE_MINOR_VERSION}")
IF("${CMAKE_VERSION}" STRGREATER "2.4")
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY /path/of/your/install/${CMAKE_BUILD_TYPE}/bin)
SET(CMAKE_LIBRARY_OUTPUT_PATH /path/of/your/install/${CMAKE_BUILD_TYPE}/lib)
ELSE("${CMAKE_VERSION}" STRGREATER "2.4")
SET(EXECUTABLE_OUTPUT_PATH /path/of/your/install/${CMAKE_BUILD_TYPE}/bin)
SET(LIBRARY_OUTPUT_PATH /path/of/your/install/${CMAKE_BUILD_TYPE}/lib)
ENDIF("${CMAKE_VERSION}" STRGREATER "2.4")
What about using the various CMAKE_INSTALL_PREFIX, PROJECT_SOURCE_DIR and PROJECT_BINARY_DIR?