diff --git a/INSTALL b/INSTALL index 43049ec4ea1..61b05d8a739 100644 --- a/INSTALL +++ b/INSTALL @@ -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 ====================== diff --git a/cmake/CreateQgsVersion.cmake b/cmake/CreateQgsVersion.cmake index 5748e54b26a..e9319f5dbbe 100644 --- a/cmake/CreateQgsVersion.cmake +++ b/cmake/CreateQgsVersion.cmake @@ -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) diff --git a/ms-windows/mxe/README b/ms-windows/mxe/README new file mode 100644 index 00000000000..71b681b1acc --- /dev/null +++ b/ms-windows/mxe/README @@ -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. diff --git a/ms-windows/mxe/build-mxe.sh b/ms-windows/mxe/build-mxe.sh new file mode 100755 index 00000000000..a2bad5aec84 --- /dev/null +++ b/ms-windows/mxe/build-mxe.sh @@ -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." diff --git a/ms-windows/mxe/deploy.py b/ms-windows/mxe/deploy.py new file mode 100644 index 00000000000..77903eafc36 --- /dev/null +++ b/ms-windows/mxe/deploy.py @@ -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() diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 983ce72e4ea..ad189c04470 100755 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -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) diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index 4de33dcc8a3..5b9a4a4ade6 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -431,7 +431,7 @@ extern "C" #include #else #include -#include +#include #endif class QTreeWidgetItem; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 86443725955..070c09f3ec8 100755 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -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) diff --git a/src/core/qgsapplication.cpp b/src/core/qgsapplication.cpp index e1b4db8d26f..5f652979c79 100644 --- a/src/core/qgsapplication.cpp +++ b/src/core/qgsapplication.cpp @@ -69,9 +69,9 @@ #else #include #include -#include +#include #define SECURITY_WIN32 -#include +#include #pragma comment( lib, "Secur32.lib" ) #endif diff --git a/src/crashhandler/CMakeLists.txt b/src/crashhandler/CMakeLists.txt index e034a4a024f..15e7299b9e3 100644 --- a/src/crashhandler/CMakeLists.txt +++ b/src/crashhandler/CMakeLists.txt @@ -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 ...\")")