From 32a6ab1f3b23b816881d02cca29afcec280408d4 Mon Sep 17 00:00:00 2001
From: Stephen Kelly <stephen.kelly@energid.com>
Date: Fri, 24 Jan 2020 16:18:39 +0000
Subject: QNX: Add support for CMAKE_SYSROOT

QCC is a wrapper around GCC, but it is not a fully transparent wrapper.
Some compile options need to be passed to GCC using a `-Wc` option.

QCC does not support --sysroot, so setting CMAKE_SYSROOT in a toolchain
file currently does not work.  This means that it is likely that no one
is setting CMAKE_SYSROOT in existing QNC toolchain files.  Override the
GCC option for sysroot in the QCC.cmake file with -Wc,-isysroot.

This exposes a further issue in that the QNX SDK does not follow the
same architectural folder structure as linux uses.  That is, on linux
systems, architecture-specific libraries might be in

    <sysroot>/usr/lib/<arch>

such as

    /usr/lib/x86_64-linux-gnu/libcurl.so

CMake models this by suffixing the <arch> onto lib directories when
searching for libraries.

The QNX SDK is structured differently such that the <arch> should be
used as a prefix:

    <sysroot>/<arch>/usr/lib

such as

    <sysroot>/x86_64/usr/lib/libcurl.so

Add a variable for platform configuration to set whether to prefix or
suffix the <arch> and set that in the QCC.cmake.

Use the directory structure of the QNX SDK to compute the <arch> from
the implicit library directories.  The assumption is that the arch will
be a single directory directly below the CMAKE_SYSROOT, below which the
usr/ prefix occurs.

It would not be appropriate to instruct users to make the <arch> part of
the sysroot when specified in the toolchain file because:

1.  That would be non-DRY - The QCC wrapper already determines the <arch>
    by the -V argument passed to the compiler, specified in the toolchain
    file as the CMAKE_C_COMPILER_TARGET variable.
2.  The includes in the QNX SDK are not below the <arch> directory.

So, the location of the <arch> in the full path is different on QNX
compared to, say an embedded linux platform, but the intent is the same.

Add documentation to recommend the use of CMAKE_SYSROOT in a QNX
toolchain file.

As the CMAKE_SYSROOT is always the same for QNX, it would be possible to
simply set it in QCC.cmake.  However, that would change behavior for
existing users as when CMAKE_SYSROOT is set, files/paths outside of the
CMAKE_SYSROOT do not get found.

The <arch> prefixing is only enabled in cmSearchPath.cxx if
CMAKE_SYSROOT is set.  This ensures that the user gets consistency in
the current state without CMAKE_SYSROOT, and gets better consistency
when using CMAKE_SYSROOT.
---
 Help/manual/cmake-toolchains.7.rst      |  3 +++
 Modules/CMakeDetermineCompilerABI.cmake | 12 ++++++++++++
 Modules/Compiler/QCC.cmake              |  3 +++
 Source/cmSearchPath.cxx                 |  8 +++++++-
 4 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/Help/manual/cmake-toolchains.7.rst b/Help/manual/cmake-toolchains.7.rst
index f233d08..e8badd4 100644
--- a/Help/manual/cmake-toolchains.7.rst
+++ b/Help/manual/cmake-toolchains.7.rst
@@ -233,6 +233,9 @@ value to those supported compilers when compiling:
   set(CMAKE_CXX_COMPILER QCC)
   set(CMAKE_CXX_COMPILER_TARGET ${arch})
 
+  set(CMAKE_SYSROOT $ENV{QNX_TARGET})
+
+
 Cross Compiling for Windows CE
 ------------------------------
 
diff --git a/Modules/CMakeDetermineCompilerABI.cmake b/Modules/CMakeDetermineCompilerABI.cmake
index c5611b5..99447e4 100644
--- a/Modules/CMakeDetermineCompilerABI.cmake
+++ b/Modules/CMakeDetermineCompilerABI.cmake
@@ -161,6 +161,18 @@ function(CMAKE_DETERMINE_COMPILER_ABI lang src)
             break()
           endif()
         endforeach()
+      elseif(CMAKE_CXX_COMPILER_ID STREQUAL QCC)
+        foreach(dir ${implicit_dirs})
+          if (dir MATCHES "/lib$")
+            get_filename_component(assumedArchDir "${dir}" DIRECTORY)
+            get_filename_component(archParentDir "${assumedArchDir}" DIRECTORY)
+            if (archParentDir STREQUAL CMAKE_SYSROOT)
+              get_filename_component(archDirName "${assumedArchDir}" NAME)
+              set(CMAKE_${lang}_LIBRARY_ARCHITECTURE "${archDirName}" PARENT_SCOPE)
+              break()
+            endif()
+          endif()
+        endforeach()
       endif()
 
     else()
diff --git a/Modules/Compiler/QCC.cmake b/Modules/Compiler/QCC.cmake
index 9df8269..10e1389 100644
--- a/Modules/Compiler/QCC.cmake
+++ b/Modules/Compiler/QCC.cmake
@@ -10,6 +10,9 @@ macro(__compiler_qcc lang)
   # http://www.qnx.com/developers/docs/6.4.0/neutrino/utilities/q/qcc.html#examples
   set(CMAKE_${lang}_COMPILE_OPTIONS_TARGET "-V")
 
+  set(CMAKE_PREFIX_LIBRARY_ARCHITECTURE "ON")
+
+  set(CMAKE_${lang}_COMPILE_OPTIONS_SYSROOT "-Wc,-isysroot,")
   set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-Wp,-isystem,")
   set(CMAKE_DEPFILE_FLAGS_${lang} "-Wp,-MD,<DEPFILE> -Wp,-MT,<OBJECT> -Wp,-MF,<DEPFILE>")
 
diff --git a/Source/cmSearchPath.cxx b/Source/cmSearchPath.cxx
index d15ce57..766d347 100644
--- a/Source/cmSearchPath.cxx
+++ b/Source/cmSearchPath.cxx
@@ -181,7 +181,13 @@ void cmSearchPath::AddPrefixPaths(const std::vector<std::string>& paths,
       const char* arch =
         this->FC->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE");
       if (arch && *arch) {
-        this->AddPathInternal(dir + subdir + "/" + arch, base);
+        if (this->FC->Makefile->IsDefinitionSet("CMAKE_SYSROOT") &&
+            this->FC->Makefile->IsDefinitionSet(
+              "CMAKE_PREFIX_LIBRARY_ARCHITECTURE")) {
+          this->AddPathInternal(cmStrCat('/', arch, dir, subdir), base);
+        } else {
+          this->AddPathInternal(cmStrCat(dir, subdir, '/', arch), base);
+        }
       }
     }
     std::string add = dir + subdir;
-- 
cgit v0.12