diff --git a/CMakeLists.txt b/CMakeLists.txt index dd775a7ac5..8e23bd58fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,24 +1,27 @@ # Copyright (c) 2017 The Bitcoin developers cmake_minimum_required(VERSION 3.5) project(BitcoinABC) # Add path for custom modules set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules ) +# Make contrib script accessible. +set(CONTRIB_PATH ${CMAKE_CURRENT_SOURCE_DIR}/contrib) + # If ccache is available, then use it. find_program(CCACHE ccache) if(CCACHE) set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE}) set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE}) endif(CCACHE) # Add the magic taret check and check-all add_custom_target(check-all) add_custom_target(check) add_subdirectory(src) add_subdirectory(test) diff --git a/contrib/qt/convert-prl-libs-to-cmake.pl b/contrib/qt/convert-prl-libs-to-cmake.pl new file mode 100755 index 0000000000..54897826c9 --- /dev/null +++ b/contrib/qt/convert-prl-libs-to-cmake.pl @@ -0,0 +1,133 @@ +#!/usr/bin/env perl +# Copyright (C) 2016 Konstantin Tokarev +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. + +use File::Basename; +use File::Spec; +use Getopt::Long; +use Text::ParseWords; + +use v5.10; + +use strict; +use warnings; + +my $qt_lib; +my $component_name; +my $out_name; +my $compiler; + +processArgs(); + +sub processArgs { + GetOptions ( + "lib=s" => \$qt_lib, + "component=s" => \$component_name, + "out=s" => \$out_name, + "compiler=s" => \$compiler + ) +} + +my $qt_lib_dir = dirname($qt_lib); +my $qt_lib_base = fileparse($qt_lib, qr{\..*}); +my $prl_name = File::Spec->join($qt_lib_dir, "$qt_lib_base.prl"); + +# Some versions of Qt remove the lib prefix on some plateforms. +if (! -r $prl_name) { + $qt_lib_base =~ s/^lib//; + $prl_name = File::Spec->join($qt_lib_dir, "$qt_lib_base.prl"); +} + +my $qmake_prl_libs; + +open(my $prl, '<', $prl_name) or die "Cannot open $prl_name: $!"; +while (<$prl>) { + next unless /^QMAKE_PRL_LIBS/; + chomp; + if (/^QMAKE_PRL_LIBS\s+=\s+(.*)$/) { + $qmake_prl_libs = $1; + last; + } +} +close $prl; + +unless ($qmake_prl_libs) { + print "QMAKE_PRL_LIBS variable is undefined or empty\n"; + exit; +} + +my $prl_libs = squash_prl_libs(shellwords($qmake_prl_libs)); + +my $template = <<'END_CMAKE'; +get_target_property(_link_libs Qt5::${_component} INTERFACE_LINK_LIBRARIES) +if (_link_libs) + set(_list_sep ";") +else () + set(_list_sep "") +endif () +set_target_properties(Qt5::${_component} PROPERTIES + "INTERFACE_LINK_LIBRARIES" "${_link_libs}${_list_sep}${_libs}") +set(Qt5${_component}_STATIC_LIB_DEPENDENCIES "${_libs}") +list(APPEND STATIC_LIB_DEPENDENCIES + ${Qt5${_component}_STATIC_LIB_DEPENDENCIES} +) +unset(_component) +unset(_libs) +unset(_list_sep) + +END_CMAKE + +open(my $out, '>>', $out_name) or die "Cannot open $out_name for writing: $!"; +print $out qq/set(_component "$component_name")\n/; +print $out qq/set(_libs "$prl_libs")\n/; +print $out qq/set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "$prl_name")\n/; +print $out $template; +close $out; + +sub squash_prl_libs { + my @libs = @_; + my @result; + for (my $i = 0; $i < scalar(@libs); ++$i) { + my $lib = $libs[$i]; + if ($lib eq '-framework') { + $lib = "$libs[$i] $libs[$i + 1]"; + ++$i; + } + $lib =~ s"\$\$\[QT_INSTALL_LIBS\]"$qt_lib_dir"g; + + if (lc($compiler) eq 'msvc') { + # convert backslashes + $lib =~ s"\\"/"g; + + # MSVC doesn't support -L and -l arguments + if ($lib =~ /^-L(.*)$/) { + $lib = "-LIBPATH:$1" + } else { + $lib =~ s/^-l//; + } + } + + push @result, $lib; + } + return join ';', @result; +} diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index 73ba199be6..5e4bf7bf0a 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -1,169 +1,217 @@ # Copyright (c) 2018 The Bitcoin developers project(bitcoin-qt) # This ensure that AUTOMOC doesn't run on generated files. cmake_policy(SET CMP0071 OLD) include(BrewHelper) find_brew_prefix(QT5_PREFIX qt5) -find_package(Qt5 COMPONENTS Widgets Network REQUIRED HINTS "${QT5_PREFIX}") + +set(QT_REQUIRED_COMPONENTS Core Widgets Network) +find_package(Qt5 COMPONENTS ${QT_REQUIRED_COMPONENTS} REQUIRED HINTS "${QT5_PREFIX}") + +# Find out more about Qt. This is similar to +# http://code.qt.io/cgit/qt/qtwebkit.git/tree/Source/cmake/OptionsQt.cmake +get_target_property(QT_CORE_TYPE Qt5::Core TYPE) +if(QT_CORE_TYPE MATCHES STATIC) + set(QT_STATIC_BUILD ON) +endif() + +set(STATIC_DEPENDENCIES_CMAKE_FILE "${CMAKE_BINARY_DIR}/QtStaticDependencies.cmake") +if(EXISTS ${STATIC_DEPENDENCIES_CMAKE_FILE}) + file(REMOVE ${STATIC_DEPENDENCIES_CMAKE_FILE}) +endif() + +set(CONVERT_PRL_PATH "${CONTRIB_PATH}/qt/convert-prl-libs-to-cmake.pl") +macro(CONVERT_PRL_LIBS_TO_CMAKE _qt_component) + if(TARGET Qt5::${_qt_component}) + get_target_property(_lib_location Qt5::${_qt_component} LOCATION) + execute_process(COMMAND ${PERL_EXECUTABLE} "${CONVERT_PRL_PATH}" + --lib ${_lib_location} + --out ${STATIC_DEPENDENCIES_CMAKE_FILE} + --component ${_qt_component} + --compiler ${CMAKE_CXX_COMPILER_ID} + ) + endif() +endmacro() + +if(QT_STATIC_BUILD) + foreach(qt_module ${QT_REQUIRED_COMPONENTS}) + CONVERT_PRL_LIBS_TO_CMAKE(${qt_module}) + endforeach() + # HACK: We must explicitly add LIB path of the Qt installation + # to correctly find qtpcre + link_directories(${_qt5_install_prefix}/../) + + # Now that we generated the dependencies, import them. + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${CONVERT_PRL_PATH}") + if(NOT EXISTS ${STATIC_DEPENDENCIES_CMAKE_FILE}) + message(FATAL_ERROR "Unable to find ${STATIC_DEPENDENCIES_CMAKE_FILE}") + endif() + include(${STATIC_DEPENDENCIES_CMAKE_FILE}) + list(REMOVE_DUPLICATES STATIC_LIB_DEPENDENCIES) +endif() # Localisation add_subdirectory(locale) add_custom_command(OUTPUT temp_bitcoin_locale.qrc COMMAND cmake ARGS -E copy "${CMAKE_CURRENT_SOURCE_DIR}/bitcoin_locale.qrc" temp_bitcoin_locale.qrc MAIN_DEPENDENCY bitcoin_locale.qrc VERBATIM ) add_custom_command(OUTPUT qrc_bitcoin_locale.cpp COMMAND Qt5::rcc ARGS temp_bitcoin_locale.qrc -name bitcoin_locale -o qrc_bitcoin_locale.cpp MAIN_DEPENDENCY temp_bitcoin_locale.qrc DEPENDS locales VERBATIM ) # UI elements qt5_wrap_ui(UI_GENERATED_HEADERS forms/addressbookpage.ui forms/askpassphrasedialog.ui forms/coincontroldialog.ui forms/editaddressdialog.ui forms/helpmessagedialog.ui forms/intro.ui forms/modaloverlay.ui forms/openuridialog.ui forms/optionsdialog.ui forms/overviewpage.ui forms/receivecoinsdialog.ui forms/receiverequestdialog.ui forms/debugwindow.ui forms/sendcoinsdialog.ui forms/sendcoinsentry.ui forms/signverifymessagedialog.ui forms/transactiondescdialog.ui ) # Qt MOC set(CMAKE_AUTOMOC ON) # Handle qrc resources qt5_add_resources(QRC_BITCOIN_CPP bitcoin.qrc) # Do protobuf codegen find_package(Protobuf REQUIRED) protobuf_generate_cpp(PROTOBUF_SOURCES PROTOBUF_HEADERS paymentrequest.proto) add_library(bitcoin-qt-base bantablemodel.cpp bitcoinaddressvalidator.cpp bitcoinamountfield.cpp bitcoingui.cpp bitcoinunits.cpp clientmodel.cpp csvmodelwriter.cpp guiutil.cpp intro.cpp modaloverlay.cpp networkstyle.cpp notificator.cpp optionsdialog.cpp optionsmodel.cpp peertablemodel.cpp platformstyle.cpp qvalidatedlineedit.cpp qvaluecombobox.cpp rpcconsole.cpp splashscreen.cpp trafficgraphwidget.cpp utilitydialog.cpp # Handle ui files ${UI_GENERATED_HEADERS} # Protobuf codegen ${PROTOBUF_HEADERS} ${PROTOBUF_SOURCES} # Translations ${BITCOIN_QM_FILES} # Handle qrc files ${QRC_BITCOIN_CPP} qrc_bitcoin_locale.cpp ) # Windows support if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") target_sources(bitcoin-qt-base PRIVATE winshutdownmonitor.cpp) endif() target_include_directories(bitcoin-qt-base PUBLIC . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/forms ${Protobuf_INCLUDE_DIRS} ) target_link_libraries(bitcoin-qt-base server rpcclient Qt5::Widgets Qt5::Network OpenSSL::SSL ${Protobuf_LIBRARIES} ) if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set_property(TARGET bitcoin-qt-base PROPERTY AUTOMOC_MOC_OPTIONS "-DQ_OS_MAC") endif() # Wallet if(BUILD_BITCOIN_WALLET) # Automoc option. set(AUTOMOC_MOC_OPTIONS -DENABLE_WALLET=1) # Add wallet functionality to bitcoin-qt target_sources(bitcoin-qt-base PRIVATE addressbookpage.cpp addresstablemodel.cpp askpassphrasedialog.cpp coincontroldialog.cpp coincontroltreewidget.cpp editaddressdialog.cpp openuridialog.cpp overviewpage.cpp paymentrequestplus.cpp paymentserver.cpp receivecoinsdialog.cpp receiverequestdialog.cpp recentrequeststablemodel.cpp sendcoinsdialog.cpp sendcoinsentry.cpp signverifymessagedialog.cpp transactiondesc.cpp transactiondescdialog.cpp transactionfilterproxy.cpp transactionrecord.cpp transactiontablemodel.cpp transactionview.cpp walletframe.cpp walletmodel.cpp walletmodeltransaction.cpp walletview.cpp ) target_link_libraries(bitcoin-qt-base wallet) endif() + +# The executable +add_executable(bitcoin-qt bitcoin.cpp) +target_link_libraries(bitcoin-qt bitcoin-qt-base)