Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A simple example of using cmake to build a Windows DLL

A couple of years ago I was saddled with building and modifying this huge package from a partner engineering institution located in the NorthEast (perhaps, "Down East"). This package was built using something called "cmake" with Linux as the target... cmake, IMHO the most amazingly maddening, poorly documented, oddly structured build system I'd ever had the displeasure of working with given my limited abilities (28 years of professional experience with *NIX systems and building lotsa open source code).

Then I had to build another project with "cmake" which targeted MSVS. Oh, the JOY! Finally SOMETHING that could reliably generate those nasty-a**ed "project" and "solution" files. And those same CMakeLists.txt files could re-target Linux! Wow, I've seen the light.

It's still pretty dark where I am, though. Unless I have a CMakeLists.txt file to start with, I just can't seem to get my head wrapped around starting one from scratch and spending less than a day on that process for the simplest problem.

I have a task to build a DLL with MSVS that can be accessed from a Python script using ctypes. Basically, that means a DLL which has symbols on-board. Since I have that 10-year-old bug where my installations of VS 2008 AND VS 2010 cannot create a new C++ project, I figured I'd bend my pick on generating a DLL Solution with cmake.

I haven't been able to find a modern (aka post cmake 2.8.5) COMPLETE example of building a DLL with cmake, which is supposed to be much better at this task than in the past.

Dived through the tutorial http://www.cmake.org/cmake/help/cmake_tutorial.html which is horrible because they expect you to write the C++ code while learning the cmake. (Hey, man! I'm having enough trouble getting cmake to work let along make code that will compile!) The tutorial goes though building a simple binary and then a binary using a library, but it does not generate a DLL.

Reading http://www.cmake.org/Wiki/BuildingWinDLL between the lines, I naively added some code to the CMakeLists.txt file in the lib directory:

Before:

add_library(MathFunctions mysqrt.cxx)

install (TARGETS MathFunctions DESTINATION bin)
install (FILES MathFunctions.h DESTINATION include)

After:

add_library(MathFunctions SHARED mysqrt.cxx)
GENERATE_EXPORT_HEADER( MathFunctions
             BASE_NAME MathFunctions
             EXPORT_MACRO_NAME MathFunctions_EXPORT
             EXPORT_FILE_NAME MathFunctions_Export.h
             STATIC_DEFINE MathFunctions_BUILT_AS_STATIC
)
install (TARGETS MathFunctions DESTINATION bin)
install (FILES MathFunctions.h DESTINATION include)

cmake 3.0.0 and cmake 2.8.12.2 both winge at this file with:

CMake Error at MathFunctions/CMakeLists.txt:2 (GENERATE_EXPORT_HEADER):
  Unknown CMake command "GENERATE_EXPORT_HEADER".

The function appears to be in the cmake installation as GenerateExportHeader.cmake, and no amount of debugging revealed the "why" on this error. And I haven't been able to find this error on the Internet.

And that was the first six hours of my day.

I finally decided to remove the offending command and try this:

add_library(MathFunctions mysqrt.cxx)

install (TARGETS MathFunctions DESTINATION bin)
install (FILES MathFunctions.h DESTINATION include)

Wa-la! cmake configured and generated and MSVS built it successfully and a DLL appeared in the Debug subdirectory of the library directory. Kuel.

This DLL, however, did not contain the symbols that would allow python/ctypes to access the desired function. After some more rooting around in the BuildingWinDLL page, I managed to elicit the symbols. Python was very happy, and I now have a model for future work even though it is a rude, simple-minded hack!

SO, after that long-winded discussion:

  • Is the BuildingWinDLL, referring to cmake 2.8.5 and above, simply wrong?
  • What was the right way to do this?
  • Does anybody out there have a simple, "cmake 101" example of creating an MSVS DLL with exported symbols that is not a hack so that I can throw away my hack?

PS: very, nice, friendly article composition system here at stackoverflow. I will enjoy this, assuming I'm allowed back...

UPDATE after the answer from steveire:

The original question answered, and I see that I missed a hint in the BuildingWinDLL page. I also have found that I failed to change one of the fields in the example for my own code.

So now we're on to the next layer. Using the referenced example, the VS2010 solution build complains:

LINK : fatal error LNK1104: cannot open file 'MathFunctions\Debug\MathFunctions.lib'

I gathered from the BuildingWinDLL that the GENERATE_EXPORT_HEADER() was all-singing, all-dancing with regard to building the DLL. The .lib file is not being generated, and the .dll that is generated does not contain symbols...

The BuildingWinDLL page talks about the pre-cmake-2.8.5 process. The 2.8.5 process noted at the top of the page is how the files at the bottom of the page are now automatically generated using GENERATE_EXPORT_HEADER(). It is still necessary to knit the pieces together, which is not clear to me from the text.

So MathFunctions_Export.h is generated by the GENERATE_EXPORT_HEADER() cmake command and the particular parameters presented here and creates a C header with a macro for causing symbols to be exported. This file apparently has to be explicitly referred to, and symbols to export properly qualified:

#include <math.h>
#include <Mathfunctions/MathFunctions_Export.h>

MathFunctions_EXPORT double mysqrt(double v) {
    return sqrt(v);
}

Adding the #include and the *EXPORT qualifier now cause symbols to be exported, and VS now knows to generate the .lib and populate the .dll with symbols.

SUCCESS! Thanks to all who aided in this process and suffered with me in my pain.

like image 210
The Red Gator in Virginia Avatar asked Jul 21 '14 18:07

The Red Gator in Virginia


People also ask

Can CMake be used on Windows?

C++ CMake tools for Windows is installed as part of the Desktop development with C++ and Linux Development with C++ workloads. Both C++ CMake tools for Windows and Linux Development with C++ are required for cross-platform CMake development. For more information, see Install the C++ Linux workload in Visual Studio.

How do you build with CMake?

To build with just cmake change directory into where you want the binaries to be placed. For an in-place build you then run cmake and it will produce a CMakeCache. txt file that contains build options that you can adjust using any text editor.


1 Answers

include(GenerateExportHeader)

before using it.

http://www.cmake.org/cmake/help/v3.0/module/GenerateExportHeader.html

CMake builds STATIC libraries by default, so keep the SHARED if you want to build a shared library.

like image 50
steveire Avatar answered Sep 20 '22 23:09

steveire