Merge pull request #6292 from elpaso/mxe

Scripts for cross build QGIS for windows on Linux with mxe
This commit is contained in:
Alessandro Pasotti 2018-02-09 10:08:24 +01:00 committed by GitHub
commit 2a4ab6b08c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 414 additions and 21 deletions

35
INSTALL
View File

@ -23,6 +23,7 @@ Last Change : Friday February 02, 2018
4.1. Building with Microsoft Visual Studio
4.2. Building using MinGW
4.3. Creation of MSYS environment for compilation of QGIS
4.4 Building on Linux with mxe
5. Building on MacOS X
5.1. Install Developer Tools
5.2. Install Qt4 from disk image
@ -1027,6 +1028,40 @@ We're done with preparation of MSYS environment. Now you can delete all stuff in
of space and it's not necessary at all.
4.4. Building on Linux with mxe
===============================
With this approach you can build a windows binary on Linux using mxe MXE (M cross environment).
You can find the build script and a README file in the ms-windows/mxe directory.
For now, Python buildings cannot be built with mxe.
4.4.1. Initial setup
====================
Please follow the instructions on mxe website to setup your building toolchain http://mxe.cc/,
take note of the path where you have installed mxe.
4.4.2. Building the dependencies
================================
Please see the README under ms-windows/mxe for a list of the dependencies that need to be
built in mxe before attempting to build QGIS.
4.4.3. Cross-Building QGIS
==========================
Edit the build-mxe.sh script and change the path where your mxe installation is located, you
can also change the build and release directory.
4.4.4. Testing QGIS
====================
Copy and unzip the release package on a Windows machine and launch it!
5. Building on MacOS X
======================

View File

@ -2,7 +2,7 @@ MACRO(CREATE_QGSVERSION)
IF (EXISTS ${CMAKE_SOURCE_DIR}/.git/index)
FIND_PROGRAM(GITCOMMAND git PATHS c:/cygwin/bin)
IF(GITCOMMAND)
IF(WIN32)
IF(WIN32 AND NOT CMAKE_CROSS_COMPILING)
IF(USING_NINJA)
SET(ARG %a)
ELSE(USING_NINJA)
@ -16,7 +16,7 @@ MACRO(CREATE_QGSVERSION)
MAIN_DEPENDENCY ${CMAKE_SOURCE_DIR}/.git/index
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
ELSE(WIN32)
ELSE(WIN32 AND NOT CMAKE_CROSS_COMPILING)
ADD_CUSTOM_COMMAND(
OUTPUT ${CMAKE_BINARY_DIR}/qgsversion.h ${CMAKE_BINARY_DIR}/qgsversion.inc
COMMAND ${GITCOMMAND} log -n1 --pretty=\#define\\ QGSVERSION\\ \\"%h\\" >${CMAKE_BINARY_DIR}/qgsversion.h.temp
@ -26,7 +26,7 @@ MACRO(CREATE_QGSVERSION)
MAIN_DEPENDENCY ${CMAKE_SOURCE_DIR}/.git/index
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
ENDIF(WIN32)
ENDIF(WIN32 AND NOT CMAKE_CROSS_COMPILING)
ELSE(GITCOMMAND)
MESSAGE(STATUS "git marker, but no git found - version will be unknown")
IF(NOT SHA)

120
ms-windows/mxe/README Normal file
View File

@ -0,0 +1,120 @@
Scripts to cross build a windows QGIS binary from Linux using MXE:
(M cross environment) http://mxe.cc/
For now, Python bindings cannot be built with mxe.
Follow the instructions on the website to prepare the mxe environment, you
will need to build all required dependencies for QGIS.
Note that some of the packages listed below are dependencies of other
packages, you will probably not need to build them all explicitly.
armadillo
bfd
bzip2
cairo
cmake
curl
dbus
dlfcn-win32
expat
fontconfig
freetds
freetype
freexl
gcc
gdal
gendef
geos
gettext
giflib
glib
gmp
gnutls
gsl
gta
harfbuzz
hdf4
hdf5
icu4c
isl
jasper
jpeg
json-c
lcms
libffi
libgcrypt
libgeotiff
libgnurx
libgpg_error
libiconv
libidn2
libmng
libmysqlclient
libpng
libspatialindex
libssh2
libunistring
libwebp
libxml2
libzip
lzo
mpc
mpfr
netcdf
nettle
openblas
openjpeg
openssl
pcre
pcre2
pixman
pkgconf
portablexdr
postgresql
proj
qca
qscintilla2
qt3d
qtactiveqt
qtbase
qtcanvas3d
qtcharts
qtconnectivity
qtdatavis3d
qtdeclarative
qtgamepad
qtgraphicaleffects
qtimageformats
qtkeychain
qtlocation
qtmultimedia
qtpurchasing
qtquickcontrols
qtquickcontrols2
qtscript
qtscxml
qtsensors
qtserialbus
qtserialport
qtspeech
qtsvg
qttools
qttranslations
qtvirtualkeyboard
qtwebchannel
qtwebkit
qtwebsockets
qtwebview
qtwinextras
qtxmlpatterns
qwt
spatialite
sqlite
tiff
xz
zlib
When done, you can edit the build-mxe.sh script to set the path to your mxe installation.

105
ms-windows/mxe/build-mxe.sh Executable file
View File

@ -0,0 +1,105 @@
#!/bin/bash
###########################################################################
# build-mxe.sh
# ---------------------
# Date : February 2018
# Copyright : (C) 2018 by Alessandro Pasotti
# Email : elpaso at itopen dot it
###########################################################################
# #
# This program is free software; you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation; either version 2 of the License, or #
# (at your option) any later version. #
# #
###########################################################################
set -e
# Usage: you can pass an optional "package" command to skip the build
# and directly go to the packaging
# This script needs to be called from the main QGIS directory, the
# one which contains CMakeLists.txt
COMMAND=$1
# Location of current script
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
PYDEPLOY=${DIR}/deploy.py
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# Configuration: change this!
# Location of mxe install dir
MXE=${HOME}/dev/mxe/
# Where the artifact will be saved
BUILD_DIR=`pwd`/build-mxe
RELEASE_DIR=`pwd`/release-mxe
# End configuration
if [[ "$COMMAND" != *"package"* ]]; then
[ -d $BUILD_DIR ] && rm -rf $BUILD_DIR
[ -d $RELEASE_DIR ] && rm -rf $RELEASE_DIR
# Make sure dirs exist
[ -d $BUILD_DIR ] || mkdir $BUILD_DIR
[ -d $RELEASE_DIR ] || mkdir $RELEASE_DIR
[ -d $RELEASE_DIR/qt5 ] || mkdir $RELEASE_DIR/qt5
fi
pushd .
cd $BUILD_DIR
# Build
if [[ "$COMMAND" != *"package"* ]]; then
$MXE/usr/bin/i686-w64-mingw32.shared-cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=$RELEASE_DIR \
-DENABLE_TESTS=OFF \
-DWITH_QSPATIALITE=ON \
-DWITH_APIDOC=OFF \
-DWITH_QWTPOLAR=ON \
-DWITH_ASTYLE=OFF \
-DWITH_SERVER=OFF \
-DWITH_BINDINGS=FALSE \
-DQT_LRELEASE_EXECUTABLE=$MXE/usr/i686-w64-mingw32.shared/qt5/bin/lrelease \
$ARGS
make -j16 install
fi
# Collect deps
$PYDEPLOY --build=$RELEASE_DIR --objdump=$MXE/usr/bin/i686-w64-mingw32.shared-objdump ${RELEASE_DIR}/qgis.exe
for dll in $(ls ${RELEASE_DIR}/*.dll); do \
$PYDEPLOY --build=$RELEASE_DIR --objdump=$MXE/usr/bin/i686-w64-mingw32.shared-objdump $dll; \
done
cp -r $MXE/usr/i686-w64-mingw32.shared/qt5/plugins $RELEASE_DIR/qt5
cat <<__TXT__ > ${RELEASE_DIR}/qt.conf
[Paths]
Plugins = qt5
__TXT__
popd
ZIP_NAME=release-`date +%Y-%m-%d-%H-%I-%S`.zip
zip -r $ZIP_NAME $RELEASE_DIR
echo "Release in $ZIP_NAME ready."

128
ms-windows/mxe/deploy.py Normal file
View File

@ -0,0 +1,128 @@
#! /usr/bin/env python3
"""pyWindeployqt
This is a wrapper for mingw32 objdump replacing windeployqt which is missing from MXE
I don't know why they disabled it, but here it is.
Example:
./deploy.py --build=~/ClionProjects/project/build/ \
--objdump=/home/user/mxe/usr/bin/i686-w64-mingw32.shared-objdump \
~/ClionProjects/project/build/project.exe;
"""
__author__ = 'Alexey Elymanov (strangeqargo@gmail.com)'
import subprocess
import os
import sys
import re
import os.path
import argparse
parser = argparse.ArgumentParser()
parser.add_argument(
"--build", help="where to place libraries, optional, files will go to target location by default")
parser.add_argument(
"--objdump", help="objdump executable (/home/user/mxe/usr/bin/i686-w64-mingw32.shared-objdump)")
parser.add_argument(
"--libs", help="where to search for libraries (optional) infers from objdump")
parser.add_argument("target")
args = parser.parse_args()
if len(sys.argv) == 1 or not (args.libs or args.objdump):
parser.print_help()
sys.exit(1)
target = os.path.expanduser(args.target)
objdump_path = os.path.expanduser(args.objdump)
if not args.build:
build_path = os.path.expanduser(os.path.dirname(args.target)) + "/"
else:
build_path = os.path.expanduser(args.build)
libs = args.libs
if not args.libs:
libs = objdump_path.replace('/bin', '').replace('-objdump', '')
# build_path = "/home/user/ClionProjects/project/build/"
# libs = "/home/user/mxe/usr/i686-w64-mingw32.shared"
# objdump_path = "/home/user/mxe/usr/bin/i686-w64-mingw32.shared-objdump"
# target = "project.exe"
def run_check():
return subprocess.getoutput("wine project.exe")
def find_dll(dll):
out = subprocess.getoutput("find " + libs + " | grep -i '" + dll + "$'")
return out.strip('\n')
def library_install_exe(out=''):
out = run_check().splitlines()
for line in out:
# err = re.search('(err:module:import_dll (Library |Loading library)) (.*?\.dll) ', line)
err = re.search('([^ ]+\.dll) \(which', line)
if err is not None:
dll = err.group(1)
dll = find_dll(dll)
if dll is not None:
copy_command = "cp " + dll + " " + build_path
print("copy: ", copy_command)
subprocess.getoutput(copy_command)
library_install_exe(out)
def library_install_objdump(path, level):
if path in skip_libs or path in done:
return
if level > 0:
lib = find_dll(path)
if lib == "": # not found
skip_libs.append(path)
print("Not found: " + path)
return
print(lib)
subprocess.getoutput("cp " + lib + " " + build_path)
else:
print("Processing target " + path)
lib = path
done.append(path)
command = objdump_path + " -p " + lib + " | grep -o ': .*\.dll$'"
res = subprocess.getstatusoutput(command)
if (res[0] > 0):
print("Error: objdump failed with " + lib)
else:
dlls = subprocess.getoutput(command).split("\n")
for line in dlls:
dll = (line.split(": "))[1]
if dll not in done and dll not in skip_libs:
level += 1
library_install_objdump(dll, level)
skip_libs = list()
done = list()
def main():
os.chdir(build_path)
# library_install_exe(target)
library_install_objdump(target, 0)
pass
main()

View File

@ -522,17 +522,22 @@ IF (WIN32)
IF (NOT WINDRES)
FIND_PROGRAM(WINDRES windres)
IF (NOT WINDRES)
IF (NOT WINDRES AND NOT CMAKE_RC_COMPILER)
MESSAGE(FATAL_ERROR "windres not found - aborting")
ENDIF (NOT WINDRES)
ENDIF (NOT WINDRES AND NOT CMAKE_RC_COMPILER)
ENDIF (NOT WINDRES)
#############################################################
# application icon
# resource compilation for MinGW
ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/icon.o
COMMAND ${WINDRES} -I${CMAKE_CURRENT_SOURCE_DIR} -i${CMAKE_CURRENT_SOURCE_DIR}/qgis_win32.rc
-o ${CMAKE_CURRENT_BINARY_DIR}/icon.o )
SET(QGIS_APPMAIN_SRCS ${QGIS_APPMAIN_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/icon.o)
IF (WINDRES)
#############################################################
# application icon
# resource compilation for MinGW
ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/icon.o
COMMAND ${WINDRES} -I${CMAKE_CURRENT_SOURCE_DIR} -i${CMAKE_CURRENT_SOURCE_DIR}/qgis_win32.rc
-o ${CMAKE_CURRENT_BINARY_DIR}/icon.o )
SET(QGIS_APPMAIN_SRCS ${QGIS_APPMAIN_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/icon.o)
ELSE (WINDRES)
# MXE
ENDIF (WINDRES)
ENDIF (MSVC)
ELSE(WIN32)
SET (QGIS_APPMAIN_SRCS main.cpp ${IMAGE_RCC_SRCS} ${TEST_RCC_SRCS})
@ -556,7 +561,7 @@ IF(PEDANTIC)
ENDIF(PEDANTIC)
IF(MSVC)
# -wd4091 Avoid 'typedef' ignored on left of '' when no variable is declared warning in DbgHelp.h
# -wd4091 Avoid 'typedef' ignored on left of '' when no variable is declared warning in dbghelp.h
SET_SOURCE_FILES_PROPERTIES(
qgisapp.cpp
main.cpp
@ -772,8 +777,8 @@ ENDIF (ANDROID)
IF(WIN32)
ADD_DEFINITIONS(-DQWT_DLL)
ADD_DEFINITIONS(-DQSCINTILLA_DLL)
TARGET_LINK_LIBRARIES(${QGIS_APP_NAME} DbgHelp)
TARGET_LINK_LIBRARIES(qgis_app DbgHelp Qt5::WinExtras)
TARGET_LINK_LIBRARIES(${QGIS_APP_NAME} dbghelp)
TARGET_LINK_LIBRARIES(qgis_app dbghelp Qt5::WinExtras)
ENDIF(WIN32)
TARGET_LINK_LIBRARIES(${QGIS_APP_NAME} qgis_native)

View File

@ -431,7 +431,7 @@ extern "C"
#include <dlfcn.h>
#else
#include <windows.h>
#include <DbgHelp.h>
#include <dbghelp.h>
#endif
class QTreeWidgetItem;

View File

@ -1254,7 +1254,7 @@ ADD_DEPENDENCIES(qgis_core version)
# because of htonl
IF (WIN32)
FIND_LIBRARY(SETUPAPI_LIBRARY NAMES setupapi PATHS $ENV{LIB})
TARGET_LINK_LIBRARIES(qgis_core wsock32 ${SETUPAPI_LIBRARY} DbgHelp)
TARGET_LINK_LIBRARIES(qgis_core wsock32 ${SETUPAPI_LIBRARY} dbghelp)
ENDIF (WIN32)
IF (APPLE)

View File

@ -69,9 +69,9 @@
#else
#include <winsock.h>
#include <windows.h>
#include <Lmcons.h>
#include <lmcons.h>
#define SECURITY_WIN32
#include <Security.h>
#include <security.h>
#pragma comment( lib, "Secur32.lib" )
#endif

View File

@ -8,7 +8,7 @@ QT5_WRAP_CPP(CRASH_HDR_MOC qgscrashdialog.h)
SET(IMAGE_RCCS ../../images/images.qrc)
QT5_ADD_RESOURCES(IMAGE_RCC_SRCS ${IMAGE_RCCS})
# -wd4091 Avoid 'typedef' ignored on left of '' when no variable is declared warning in DbgHelp.h
# -wd4091 Avoid 'typedef' ignored on left of '' when no variable is declared warning in dbghelp.h
SET_SOURCE_FILES_PROPERTIES(qgsstacktrace.cpp PROPERTIES COMPILE_FLAGS -wd4091)
ADD_EXECUTABLE(qgiscrashhandler WIN32
@ -26,7 +26,7 @@ TARGET_LINK_LIBRARIES(qgiscrashhandler
${Qt5Core_LIBRARIES}
${Qt5Gui_LIBRARIES}
${Qt5Widgets_LIBRARIES}
DbgHelp
dbghelp
)
INSTALL(CODE "MESSAGE(\"Installing crashhandler ...\")")