Friday, February 21, 2014

Targeting Windows XP with Visual C++ 2013

Build apps using Visual C++ 2013 that target Windows XP, special steps are needed.

Environment Variables to Set

The following codes is quoted from this blog.

set INCLUDE=%ProgramFiles(x86)%\Microsoft SDKs\Windows\7.1A\Include;%INCLUDE%
set PATH=%ProgramFiles(x86)%\Microsoft SDKs\Windows\7.1A\Bin;%PATH%
set LIB=%ProgramFiles(x86)%\Microsoft SDKs\Windows\7.1A\Lib;%LIB%
set CL=/D_USING_V110_SDK71_;%CL%

For building x64 version, change LIB to this one.

set LIB=%ProgramFiles(x86)%\Microsoft SDKs\Windows\7.1A\Lib\x64;%LIB%

For x86 console/windows applications, set /SUBSYSTEM accordingly:

:: for console application
set LINK=/SUBSYSTEM:CONSOLE,5.01 %LINK%
:: for gui application
set LINK=/SUBSYSTEM:WINDOWS,5.01 %LINK%

For x64 console/windows applications:

:: for console application
set LINK=/SUBSYSTEM:CONSOLE,5.02 %LINK%
:: for gui application
set LINK=/SUBSYSTEM:WINDOWS,5.02 %LINK%

Work with CMake

In CMake there is a WIN32 parameter for add_executable command. It works like this:

add_executable(MyExe WIN32 main.cpp) # this exe will link with /SUBSYSTEM:WINDOWS
add_executable(AnotherExe main.cpp)  # this one will link with /SUBSYSTEM:CONSOLE

When we not target Windows XP, it works correctly. But when we target Windows XP, obviously the link flags are not correct. To fix that, we need add a file to override make rules in CMake. CMAKE_USER_MAKE_RULES_OVERRIDE_CXX is for that purpose.

In your project file, add the following code.

cmake_minimum_required(VERSION 2.8)
set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX your_path/overrides.cmake)

# please make sure the variable is set before the `project` command.
# project(MyApp) 

Then in overrides.cmake, add the following codes.

if(WIN32)
    # if target winxp
    if(TARGETING_XP_64)
        SET(CMAKE_CREATE_WIN32_EXE /SUBSYSTEM:WINDOWS,5.02)
        SET(CMAKE_CREATE_CONSOLE_EXE /SUBSYSTEM:CONSOLE,5.02)
    elif(TARGETING_XP)
        SET(CMAKE_CREATE_WIN32_EXE /SUBSYSTEM:WINDOWS,5.01)
        SET(CMAKE_CREATE_CONSOLE_EXE /SUBSYSTEM:CONSOLE,5.01)
    endif()
endif()

Now, to build targetting Windows XP, you could run cmake like the folowing.

cmake -G "YourGenerator" -DTARGETING_XP=On path_to_your_project.cmake

And the following for XP x64.

cmake -G "YourGenerator" -DTARGETING_XP_64=On path_to_your_project.cmake

Tuesday, February 18, 2014

Core Dump on Ubuntu

Listed below are just several notes about core dump on Ubuntu.

The location of core dump files

The following command can print out where will the core dump files be placed.

cat /proc/sys/kernel/core_pattern

If the output start with a | character, the kernel then will write the core dump to the stdin of the command after the | character.

Core dump file size

The following command can remove core dump file size limit.

ulimit -c unlimited

Apport

On ubuntu, core dump files are forwarded to Apport by default. So if you can’t find the core file in your current directory, you may want to try /var/crash. Probably you will see crash report files there.

The command apport-unpack can be used to extract the core files out of a crash report files.

Friday, February 14, 2014

RPATH on Windows

On Linux, we can specify shared library search paths for our executable/libraries using RPATH. On Windows, however, there is no such easy way to do that. A possible solution is to use /DELAYLOAD and SetDllDirectory.

Ways to Load a DLL

Basically speaking, there are three ways to load a DLL on windows.
- Implicitly loading. In this way, we link our application against the .lib file of the DLL. The DLL will be loaded once the application was invoked.
- Explicitly loading. That is the way we call LoadLibrary Win32 API to load a DLL. The search path can be changed by calling SetDllDirectory function.
- Delayed loading. Similar to Implicit loading, but the DLL won’t be loaded until once of functions in it got called.

Delay loading

/DELAYLOAD is a linker option of MSVC compiler (version 6 or later) that can tell the linker which DLL we want to delay load. So, to simulate the functionality of RPATH, we can specify the DLL should be delay loaded via /DELAYLOAD at link time, and call SetDllDirectory function to set the search path. After that, there are three ways to force load the library.

  • We can simply call a function that is exported in that library to force loading the library.
  • Call LoadLibrary to explicitly load the library.
  • Call __HrLoadAllImportsForDll to force load the library.

Listed below is an example to use the above method to delay load a DLL. Please note that to make the code work, delayimp.lib should be linked against.

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <delayimp.h>
#include <string>

bool loadTheLibraryNow(const char* dir) {
    const char* baseDllName = "library-to-delay-load.dll";

    if (!dir)
        return false;

    // backup current dll directory
    char previousDllDirectory[MAX_PATH] = { '\0' };
    if (!::GetDllDirectoryA(MAX_PATH, previousDllDirectory)) {
        previousDllDirectory[0] = '\0';
    }

    // set new current dll directory to
    if (!::SetDllDirectoryA(dir))
        return false;

    // force load the dll
    bool result = SUCCEEDED(__HrLoadAllImportsForDll(baseDllName));

    // restore the dll directory to old value
    ::SetDllDirectoryA(previousDllDirectory);

    return result;
}

Please See here for more details.

Build Qt5 Statically with Visual C++ 2013

1. ICU

1.1 Prerequisites

  • Download Cygwin installer from here
  • Install Cygwin and make sure make package is selected

1.2 Download ICU

  • Download ICU from here
  • Extract the zip file to C:\build\icu and make sure folder C:\build\icu\source exists
  • Open c:\build\icu\source\runConfigureICU
  • Replace all /MD to /MT (of course that will also replace /MDd to /MTd)

1.4 Build ICU

x86 version

:: Start a command prompt and setup x86 build env

cd c:\build\icu\source
set PATH=C:\cygwin\bin;%PATH%
dos2unix *
dos2unix -f configure
"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" x86

:: Build the x86 static release version

mkdir c:\build\icu\build\x86-static-release && cd c:\build\icu\build\x86-static-release
bash ../../source/runConfigureICU Cygwin/MSVC --prefix=/cygdrive/c/build/icu/dist/x86-static-release --enable-static --disable-shared
make -j8 && make install

:: Build the x86 static debug version

mkdir c:\build\icu\build\x86-static-debug && cd c:\build\icu\build\x86-static-debug
bash ../../source/runConfigureICU --enable-debug --disable-release Cygwin/MSVC --prefix=/cygdrive/c/build/icu/dist/x86-static-debug --enable-static --disable-shared 
make && make install

::

x64 version

:: Start a command prompt and setup x64 build env

cd c:\build\icu\source
set PATH=C:\cygwin\bin;%PATH%
"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" x86_amd64

:: Build the x64 static release version

mkdir c:\build\icu\build\x64-static-release && cd c:\build\icu\build\x64-static-release
bash ../../source/runConfigureICU Cygwin/MSVC --prefix=/cygdrive/c/build/icu/dist/x64-static-release --enable-static --disable-shared
make -j8 && make install

:: Build the x64 static debug version

mkdir c:\build\icu\build\x64-static-debug && cd c:\build\icu\build\x64-static-debug
bash ../../source/runConfigureICU --enable-debug --disable-release Cygwin/MSVC --prefix=/cygdrive/c/build/icu/dist/x64-static-debug --enable-static --disable-shared
make && make install

::

2. Qt

2.1 Prerequisites

2.2 Change files

  • Open c:\build\qt-everywhere-opensource-src-5.2.1\qtbase\mkspecs\win32-msvc2013\qmake.conf
    • Remove embed_manifest_dll embed_manifest_exe from the line CONFIG += line
    • Make the following change
QMAKE_CFLAGS_RELEASE    = -O2 -MD
QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -O2 -MD -Zi
QMAKE_CFLAGS_DEBUG      = -Zi -MDd

to

QMAKE_CFLAGS_RELEASE    = -O2 -MT
QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -O2 -MT -Zi -Fd$(DESTDIR)$(QMAKE_TARGET).pdb
QMAKE_CFLAGS_DEBUG      = -Zi -MTd -Fd$(DESTDIR)$(QMAKE_TARGET).pdb

2.3 Build Qt Base

x86-release version

  • Extract Qt Source to c:\build\qt-everywhere-opensource-src-5.2.1
  • Add Python, Ruby, Perl, Jom to PATH
  • Add GnuWin32 to PATH
:: Add GnuWin32 to PATH
set PATH=%PATH%;c:\build\qt-everywhere-opensource-src-5.2.1\gnuwin32\bin

:: Setup Visual C++ Environment

"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" x86

:: Add ICU to INLCUDE, LIB, PATH

set INCLUDE=%INCLUDE%;c:\build\icu\dist\x86-static-release\include
set LIB=%LIB%;c:\build\icu\dist\x86-static-release\lib
set PATH=%PATH%;c:\build\icu\dist\x86-static-release\lib

:: Add OPENSSL to INLCUDE, LIB, PATH

set INCLUDE=%INCLUDE%;c:\build\\openssl\dist\x86-static-release\include
set LIB=%LIB%;c:\build\\openssl\dist\x86-static-release\lib
set PATH=%PATH%;c:\build\\openssl\dist\x86-static-release\lib

:: Create build directory

mkdir c:\build\qt-everywhere-opensource-src-5.2.1\build\x86-static-release
cd c:\build\qt-everywhere-opensource-src-5.2.1\build\x86-static-release

:: Configure

..\..\configure -prefix c:\build\qt-everywhere-opensource-src-5.2.1\dist\x86-static-release -platform win32-msvc2013 -static -release -c++11 -opensource -confirm-license -icu -qt-zlib -qt-pcre -qt-libpng -qt-libjpeg -qt-freetype -openssl-linked -skip qtwebkit -nomake tests -nomake examples -mp -make-tool jom OPENSSL_LIBS="-lssleay32 -llibeay32 -lgdi32 -lcrypt32 -luser32 -ladvapi32"

:: Build and install

jom -j8
jom install

:: HACK: copy required libs manually

cp C:\build\qt-everywhere-opensource-src-5.2.1\build\x86-static-debug\qtbase\lib\translator_*.lib c:\build\qt-everywhere-opensource-src-5.2.1\dist\x86-static-release\lib
cp C:\build\qt-everywhere-opensource-src-5.2.1\build\x86-static-debug\qtbase\lib\preprocessor*.lib c:\build\qt-everywhere-opensource-src-5.2.1\dist\x86-static-release\lib

::

The steps to build debug version and x64 versions are similar to the ones above.

Statically Link Against an LGPL'd Library in a Closed Source Project

Statically link against a LGPL’d library in a closed source project is possible, if object format of your application is provided. In that way, a user can modify the LGPL’d library and relink the application. See GPL FAQ and here for more details.

Thursday, February 13, 2014

Test If a Type Has a Member Function

Sometimes we want to handle types with some specific member functions specially. The followin examples shows how to do that using SFINAE and enable_if.

#include <iostream>
#include <type_traits>

using namespace std;

// SFINAE test
template<typename T>
class has_test {
    template<typename U, U> class check {};
    template<typename C> static char f(check<void(C::*)(int), &C::test>*);
    template<typename C> static long f(...);
public:
    static const bool value = (sizeof(f<T>(nullptr)) == sizeof(char));
};

template<typename T>
std::enable_if_t<has_test<T>::value, void> test(T& t) {
    cout << typeid(T).name() << " has a 'test' member function. " << endl;
}

template<typename T>
std::enable_if_t<!has_test<T>::value, void> test(T& t) {
    cout << typeid(T).name() << " has no 'test' member function. " << endl;
}

struct A {
    void test(int) {}
};

struct B {
};

int main() {
    A a;
    B b;
    test(a);
    test(b);
}

Here is the output of the program.

struct A has a 'test' member function. 
struct B has no 'test' member function. 

Tuesday, February 11, 2014

Launch Program in Debugger Automatically

Sometimes I have the requirement to launch an application automatically (and always) in debugger. For example, if we have a pair of master and slave programs. The master program will start the slave program and we want to debug the slave program.

On Windows, there is a simple way to do that. Basically, we just need to add a string value Debugger=PathToYourDebugger.exe to registry under the key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\YourProgram.exe. Here, PathToYourDebugger.exe is the full path to your debugger and YourProgram.exe is the full path to your program.

After that, every time you start YourProgram.exe, the debugger will be launched.

The commands below can make it even easier.

To enable automatically-debugger-launching for a program

REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\YourProgram.exe"  /f /t REG_SZ /v debugger /d "PathToYourDebugger.exe"

To disable automatically-debugger-launching for a program

REG DELETE "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\YourProgram.exe" /f