Browse Source

Merge topic 'qt4-autolink-qtmain'

e3b5eb6 Automatically link to the qtmain library when linking to QtCore.
6c8d8af Add the $<TARGET_POLICY> expression
Brad King 12 years ago
parent
commit
a37b0e3ebf

+ 28 - 0
Modules/FindQt4.cmake

@@ -65,6 +65,12 @@
 #       is much more flexible, but requires that FindQt4.cmake is executed before
 #       such an exported dependency file is processed.
 #
+#       Note that if using IMPORTED targets, the qtmain.lib static library is
+#       automatically linked on Windows. To disable that globally, set the
+#       QT4_NO_LINK_QTMAIN variable before finding Qt4. To disable that for a
+#       particular executable, set the QT4_NO_LINK_QTMAIN target property to
+#       True on the executable.
+#
 #  QT_INCLUDE_DIRS_NO_SYSTEM
 #        If this variable is set to TRUE, the Qt include directories
 #        in the QT_USE_FILE will NOT have the SYSTEM keyword set.
@@ -1009,7 +1015,14 @@ if (QT_QMAKE_EXECUTABLE AND QTVERSION)
   # platform dependent libraries
   if(Q_WS_WIN)
     _QT4_ADJUST_LIB_VARS(qtmain)
+
     _QT4_ADJUST_LIB_VARS(QAxServer)
+    set_property(TARGET Qt4::QAxServer PROPERTY
+      INTERFACE_QT4_NO_LINK_QTMAIN ON
+    )
+    set_property(TARGET Qt4::QAxServer APPEND PROPERTY
+      COMPATIBLE_INTERFACE_BOOL QT4_NO_LINK_QTMAIN)
+
     _QT4_ADJUST_LIB_VARS(QAxContainer)
   endif()
 
@@ -1049,6 +1062,21 @@ if (QT_QMAKE_EXECUTABLE AND QTVERSION)
     _qt4_add_target_private_depends(phonon DBus)
   endif()
 
+  if (WIN32 AND NOT QT4_NO_LINK_QTMAIN)
+    set(_isExe $<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>)
+    set(_isWin32 $<BOOL:$<TARGET_PROPERTY:WIN32_EXECUTABLE>>)
+    set(_isNotExcluded $<NOT:$<BOOL:$<TARGET_PROPERTY:QT4_NO_LINK_QTMAIN>>>)
+    set(_isPolicyNEW $<TARGET_POLICY:CMP0020>)
+    set_property(TARGET Qt4::QtCore APPEND PROPERTY
+      IMPORTED_LINK_INTERFACE_LIBRARIES
+        $<$<AND:${_isExe},${_isWin32},${_isNotExcluded},${_isPolicyNEW}>:Qt4::qtmain>
+    )
+    unset(_isExe)
+    unset(_isWin32)
+    unset(_isNotExcluded)
+    unset(_isPolicyNEW)
+  endif()
+
   #######################################
   #
   #       Check the executables of Qt

+ 4 - 0
Source/cmDocumentGeneratorExpressions.h

@@ -50,6 +50,10 @@
   "  $<TARGET_PROPERTY:tgt,prop>   = The value of the property prop\n"  \
   "on the target tgt. Note that tgt is not added as a dependency of\n"  \
   "the target this expression is evaluated on.\n"                       \
+  "  $<TARGET_POLICY:pol>          = '1' if the policy was NEW when "   \
+  "the 'head' target was created, else '0'.  If the policy was not "    \
+  "set, the warning message for the policy will be emitted.  This "     \
+  "generator expression only works for a subset of policies.\n"         \
   "Boolean expressions:\n"                                              \
   "  $<AND:?[,?]...>           = '1' if all '?' are '1', else '0'\n"    \
   "  $<OR:?[,?]...>            = '0' if all '?' are '0', else '1'\n"    \

+ 101 - 0
Source/cmGeneratorExpressionEvaluator.cxx

@@ -508,6 +508,105 @@ static const struct TargetNameNode : public cmGeneratorExpressionNode
 
 } targetNameNode;
 
+//----------------------------------------------------------------------------
+static const char* targetPolicyWhitelist[] = {
+    "CMP0003"
+  , "CMP0004"
+  , "CMP0008"
+  , "CMP0020"
+};
+
+cmPolicies::PolicyStatus statusForTarget(cmTarget *tgt, const char *policy)
+{
+#define RETURN_POLICY(POLICY) \
+  if (strcmp(policy, #POLICY) == 0) \
+  { \
+    return tgt->GetPolicyStatus ## POLICY (); \
+  } \
+
+  RETURN_POLICY(CMP0003)
+  RETURN_POLICY(CMP0004)
+  RETURN_POLICY(CMP0008)
+  RETURN_POLICY(CMP0020)
+
+#undef RETURN_POLICY
+
+  assert("!Unreachable code. Not a valid policy");
+  return cmPolicies::WARN;
+}
+
+cmPolicies::PolicyID policyForString(const char *policy_id)
+{
+#define RETURN_POLICY_ID(POLICY_ID) \
+  if (strcmp(policy_id, #POLICY_ID) == 0) \
+  { \
+    return cmPolicies:: POLICY_ID; \
+  } \
+
+  RETURN_POLICY_ID(CMP0003)
+  RETURN_POLICY_ID(CMP0004)
+  RETURN_POLICY_ID(CMP0008)
+  RETURN_POLICY_ID(CMP0020)
+
+#undef RETURN_POLICY_ID
+
+  assert("!Unreachable code. Not a valid policy");
+  return cmPolicies::CMP0002;
+}
+
+//----------------------------------------------------------------------------
+static const struct TargetPolicyNode : public cmGeneratorExpressionNode
+{
+  TargetPolicyNode() {}
+
+  virtual int NumExpectedParameters() const { return 1; }
+
+  std::string Evaluate(const std::vector<std::string> &parameters,
+                       cmGeneratorExpressionContext *context ,
+                       const GeneratorExpressionContent *content,
+                       cmGeneratorExpressionDAGChecker *) const
+  {
+    if (!context->HeadTarget)
+      {
+      reportError(context, content->GetOriginalExpression(),
+          "$<TARGET_POLICY:prop> may only be used with targets.  It may not "
+          "be used with add_custom_command.");
+      return std::string();
+      }
+    for (size_t i = 0;
+         i < (sizeof(targetPolicyWhitelist) /
+              sizeof(*targetPolicyWhitelist));
+         ++i)
+      {
+      const char *policy = targetPolicyWhitelist[i];
+      if (parameters.front() == policy)
+        {
+        cmMakefile *mf = context->HeadTarget->GetMakefile();
+        switch(statusForTarget(context->HeadTarget, policy))
+          {
+          case cmPolicies::WARN:
+            mf->IssueMessage(cmake::AUTHOR_WARNING,
+                             mf->GetPolicies()->
+                             GetPolicyWarning(policyForString(policy)));
+          case cmPolicies::REQUIRED_IF_USED:
+          case cmPolicies::REQUIRED_ALWAYS:
+          case cmPolicies::OLD:
+            return "0";
+          case cmPolicies::NEW:
+            return "1";
+          }
+        }
+      }
+    reportError(context, content->GetOriginalExpression(),
+      "$<TARGET_POLICY:prop> may only be used with a limited number of "
+      "policies.  Currently it may be used with policies CMP0003, CMP0004, "
+      "CMP0008 and CMP0020."
+      );
+    return std::string();
+  }
+
+} targetPolicyNode;
+
 //----------------------------------------------------------------------------
 template<bool linker, bool soname>
 struct TargetFilesystemArtifactResultCreator
@@ -735,6 +834,8 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier)
     return &targetPropertyNode;
   else if (identifier == "TARGET_NAME")
     return &targetNameNode;
+  else if (identifier == "TARGET_POLICY")
+    return &targetPolicyNode;
   else if (identifier == "BUILD_INTERFACE")
     return &buildInterfaceNode;
   else if (identifier == "INSTALL_INTERFACE")

+ 21 - 0
Source/cmPolicies.cxx

@@ -508,6 +508,27 @@ cmPolicies::cmPolicies()
     "for strict compatibility.  "
     "The NEW behavior for this policy is to leave the values untouched.",
     2,8,11,0, cmPolicies::WARN);
+
+  this->DefinePolicy(
+    CMP0020, "CMP0020",
+    "Automatically link Qt executables to qtmain target on Windows.",
+    "CMake 2.8.10 and lower required users of Qt to always specify a link "
+    "dependency to the qtmain.lib static library manually on Windows.  CMake "
+    "2.8.11 gained the ability to evaluate generator expressions while "
+    "determining the link dependencies from IMPORTED targets.  This allows "
+    "CMake itself to automatically link executables which link to Qt to the "
+    "qtmain.lib library when using IMPORTED Qt targets.  For applications "
+    "already linking to qtmain.lib, this should have little impact.  For "
+    "applications which supply their own alternative WinMain implementation "
+    "and for applications which use the QAxServer library, this automatic "
+    "linking will need to be disabled as per the documentation."
+    "\n"
+    "The OLD behavior for this policy is not to link executables to "
+    "qtmain.lib automatically when they link to the QtCore IMPORTED"
+    "target.  "
+    "The NEW behavior for this policy is to link executables to "
+    "qtmain.lib automatically when they link to QtCore IMPORTED target.",
+    2,8,11,0, cmPolicies::WARN);
 }
 
 cmPolicies::~cmPolicies()

+ 1 - 0
Source/cmPolicies.h

@@ -69,6 +69,7 @@ public:
     /// POSITION_INDEPENDENT_CODE property and *_COMPILE_OPTIONS_PI{E,C}
     /// instead.
     CMP0019, ///< No variable re-expansion in include and link info
+    CMP0020, ///< Automatically link Qt executables to qtmain target
 
     /** \brief Always the last entry.
      *

+ 3 - 0
Source/cmTarget.cxx

@@ -145,6 +145,7 @@ cmTarget::cmTarget()
   this->PolicyStatusCMP0003 = cmPolicies::WARN;
   this->PolicyStatusCMP0004 = cmPolicies::WARN;
   this->PolicyStatusCMP0008 = cmPolicies::WARN;
+  this->PolicyStatusCMP0020 = cmPolicies::WARN;
   this->LinkLibrariesAnalyzed = false;
   this->HaveInstallRule = false;
   this->DLLPlatform = false;
@@ -1499,6 +1500,8 @@ void cmTarget::SetMakefile(cmMakefile* mf)
     this->Makefile->GetPolicyStatus(cmPolicies::CMP0004);
   this->PolicyStatusCMP0008 =
     this->Makefile->GetPolicyStatus(cmPolicies::CMP0008);
+  this->PolicyStatusCMP0020 =
+    this->Makefile->GetPolicyStatus(cmPolicies::CMP0020);
 }
 
 //----------------------------------------------------------------------------

+ 5 - 0
Source/cmTarget.h

@@ -102,6 +102,10 @@ public:
   cmPolicies::PolicyStatus GetPolicyStatusCMP0008() const
     { return this->PolicyStatusCMP0008; }
 
+  /** Get the status of policy CMP0020 when the target was created.  */
+  cmPolicies::PolicyStatus GetPolicyStatusCMP0020() const
+    { return this->PolicyStatusCMP0020; }
+
   /**
    * Get the list of the custom commands for this target
    */
@@ -658,6 +662,7 @@ private:
   cmPolicies::PolicyStatus PolicyStatusCMP0003;
   cmPolicies::PolicyStatus PolicyStatusCMP0004;
   cmPolicies::PolicyStatus PolicyStatusCMP0008;
+  cmPolicies::PolicyStatus PolicyStatusCMP0020;
 
   // Internal representation details.
   friend class cmTargetInternals;

+ 23 - 4
Tests/Qt4Targets/CMakeLists.txt

@@ -2,15 +2,16 @@ cmake_minimum_required(VERSION 2.8)
 
 project(Qt4Targets)
 
+cmake_policy(SET CMP0020 NEW)
+
 find_package(Qt4 REQUIRED)
 
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
 add_executable(Qt4Targets WIN32 main.cpp)
 target_link_libraries(Qt4Targets Qt4::QtGui)
 
-if (WIN32)
-  target_link_libraries(Qt4Targets Qt4::qtmain)
-endif()
-
 set_property(TARGET Qt4Targets APPEND PROPERTY
   INCLUDE_DIRECTORIES
     $<TARGET_PROPERTY:Qt4::QtGui,INTERFACE_INCLUDE_DIRECTORIES>
@@ -19,3 +20,21 @@ set_property(TARGET Qt4Targets APPEND PROPERTY
   COMPILE_DEFINITIONS
     $<TARGET_PROPERTY:Qt4::QtGui,INTERFACE_COMPILE_DEFINITIONS>
 )
+
+if (WIN32)
+  if (TARGET Qt4::QAxServer)
+    add_executable(activeqtexe WIN32 activeqtexe.cpp)
+    set_property(TARGET activeqtexe PROPERTY QT4_NO_LINK_QTMAIN ON)
+    target_link_libraries(activeqtexe Qt4::QAxServer Qt4::QtGui)
+    set_property(TARGET activeqtexe APPEND PROPERTY
+      INCLUDE_DIRECTORIES
+      $<TARGET_PROPERTY:Qt4::QAxServer,INTERFACE_INCLUDE_DIRECTORIES>
+      $<TARGET_PROPERTY:Qt4::QtGui,INTERFACE_INCLUDE_DIRECTORIES>
+    )
+    set_property(TARGET activeqtexe APPEND PROPERTY
+      COMPILE_DEFINITIONS
+      $<TARGET_PROPERTY:Qt4::QAxServer,INTERFACE_COMPILE_DEFINITIONS>
+      $<TARGET_PROPERTY:Qt4::QtGui,INTERFACE_COMPILE_DEFINITIONS>
+    )
+  endif()
+endif()

+ 36 - 0
Tests/Qt4Targets/activeqtexe.cpp

@@ -0,0 +1,36 @@
+
+#include <QApplication>
+
+#ifndef QT_QAXSERVER_LIB
+#error Expected QT_QAXSERVER_LIB
+#endif
+
+#include <QAxFactory>
+
+class MyObject : public QObject
+{
+ Q_OBJECT
+public:
+ MyObject(QObject *parent = 0)
+     : QObject(parent)
+ {
+ }
+};
+
+QAXFACTORY_DEFAULT(MyObject,
+                    "{4dc3f340-a6f7-44e4-a79b-3e9217685fbd}",
+                    "{9ee49617-7d5c-441a-b833-4b068d41d751}",
+                    "{13eca64b-ee2a-4f3c-aa04-5d9d975779a7}",
+                    "{ce947ee3-0403-4fdc-895a-4fe779344b46}",
+                    "{8de435ce-8d2a-46ac-b3b3-cb800d0547c7}");
+
+int main(int argc, char **argv)
+{
+  QApplication app(argc, argv);
+
+  QAxFactory::isServer();
+
+  return app.exec();
+}
+
+#include "activeqtexe.moc"

+ 1 - 0
Tests/RunCMake/CMP0004/CMP0004-NEW-result.txt

@@ -0,0 +1 @@
+1

+ 2 - 0
Tests/RunCMake/CMP0004/CMP0004-NEW-stderr.txt

@@ -0,0 +1,2 @@
+  Target "foo" links to item " bar " which has leading or trailing
+  whitespace.  This is now an error according to policy CMP0004.

+ 9 - 0
Tests/RunCMake/CMP0004/CMP0004-NEW.cmake

@@ -0,0 +1,9 @@
+
+cmake_minimum_required(VERSION 2.8)
+
+cmake_policy(SET CMP0004 NEW)
+
+add_library(foo SHARED empty.cpp)
+add_library(bar SHARED empty.cpp)
+
+target_link_libraries(foo "$<1: bar >")

+ 1 - 0
Tests/RunCMake/CMP0004/CMP0004-OLD-result.txt

@@ -0,0 +1 @@
+1

+ 2 - 0
Tests/RunCMake/CMP0004/CMP0004-OLD-stderr.txt

@@ -0,0 +1,2 @@
+  Target "bat" links to item " bar " which has leading or trailing
+  whitespace.  This is now an error according to policy CMP0004.

+ 21 - 0
Tests/RunCMake/CMP0004/CMP0004-OLD.cmake

@@ -0,0 +1,21 @@
+
+cmake_minimum_required(VERSION 2.8)
+
+cmake_policy(SET CMP0004 OLD)
+
+add_library(foo SHARED empty.cpp)
+add_library(bar SHARED empty.cpp)
+add_library(bing SHARED empty.cpp)
+add_library(bung SHARED empty.cpp)
+
+cmake_policy(SET CMP0004 NEW)
+
+add_library(bat SHARED empty.cpp)
+
+target_link_libraries(foo "$<1: bar >")
+target_link_libraries(bing "$<$<NOT:$<TARGET_POLICY:CMP0004>>: bar >")
+target_link_libraries(bung "$<$<TARGET_POLICY:CMP0004>: bar >")
+
+# The line below causes the error because the policy is NEW when bat
+# is created.
+target_link_libraries(bat "$<1: bar >")

+ 0 - 0
Tests/RunCMake/CMP0004/CMP0004-WARN-stderr.txt


+ 1 - 0
Tests/RunCMake/CMP0004/CMP0004-policy-genex-result.txt

@@ -0,0 +1 @@
+1

+ 2 - 0
Tests/RunCMake/CMP0004/CMP0004-policy-genex-stderr.txt

@@ -0,0 +1,2 @@
+  Target "foo" links to item " bat " which has leading or trailing
+  whitespace.  This is now an error according to policy CMP0004.

+ 14 - 0
Tests/RunCMake/CMP0004/CMP0004-policy-genex.cmake

@@ -0,0 +1,14 @@
+
+cmake_minimum_required(VERSION 2.8)
+
+cmake_policy(SET CMP0004 NEW)
+
+add_library(foo SHARED empty.cpp)
+add_library(bar SHARED empty.cpp)
+add_library(bat SHARED empty.cpp)
+
+# The negation here avoids the error.
+target_link_libraries(foo "$<$<NOT:$<TARGET_POLICY:CMP0004>>: bar >")
+
+# The below line causes the error.
+target_link_libraries(foo "$<$<TARGET_POLICY:CMP0004>: bat >")

+ 3 - 0
Tests/RunCMake/CMP0004/CMakeLists.txt

@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)

+ 5 - 0
Tests/RunCMake/CMP0004/RunCMakeTest.cmake

@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0004-OLD)
+run_cmake(CMP0004-NEW)
+run_cmake(CMP0004-policy-genex)

+ 0 - 0
Tests/RunCMake/CMP0004/empty.cpp


+ 1 - 0
Tests/RunCMake/CMakeLists.txt

@@ -60,6 +60,7 @@ add_RunCMake_test(find_package)
 add_RunCMake_test(include)
 add_RunCMake_test(include_directories)
 add_RunCMake_test(list)
+add_RunCMake_test(CMP0004)
 
 if("${CMAKE_TEST_GENERATOR}" MATCHES "Visual Studio [^6]")
   add_RunCMake_test(include_external_msproject)