Coverage Report

Created: 2026-02-09 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmInstallRuntimeDependencySetGenerator.cxx
Line
Count
Source
1
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2
   file LICENSE.rst or https://cmake.org/licensing for details.  */
3
#include "cmInstallRuntimeDependencySetGenerator.h"
4
5
#include <ostream>
6
#include <string>
7
#include <utility>
8
#include <vector>
9
10
#include "cmGeneratorExpression.h"
11
#include "cmInstallGenerator.h"
12
#include "cmInstallType.h"
13
#include "cmListFileCache.h"
14
#include "cmLocalGenerator.h"
15
#include "cmMakefile.h"
16
#include "cmMessageType.h"
17
#include "cmOutputConverter.h"
18
#include "cmScriptGenerator.h"
19
#include "cmStringAlgorithms.h"
20
#include "cmake.h"
21
22
cmInstallRuntimeDependencySetGenerator::cmInstallRuntimeDependencySetGenerator(
23
  DependencyType type, cmInstallRuntimeDependencySet* dependencySet,
24
  std::vector<std::string> installRPaths, bool noInstallRPath,
25
  std::string installNameDir, bool noInstallName, char const* depsVar,
26
  char const* rpathPrefix, char const* tmpVarPrefix, std::string destination,
27
  std::vector<std::string> const& configurations, std::string component,
28
  std::string permissions, MessageLevel message, bool exclude_from_all,
29
  cmListFileBacktrace backtrace)
30
0
  : cmInstallGenerator(std::move(destination), configurations,
31
0
                       std::move(component), message, exclude_from_all, false,
32
0
                       std::move(backtrace))
33
0
  , Type(type)
34
0
  , DependencySet(dependencySet)
35
0
  , InstallRPaths(std::move(installRPaths))
36
0
  , NoInstallRPath(noInstallRPath)
37
0
  , InstallNameDir(std::move(installNameDir))
38
0
  , NoInstallName(noInstallName)
39
0
  , Permissions(std::move(permissions))
40
0
  , DepsVar(depsVar)
41
0
  , RPathPrefix(rpathPrefix)
42
0
  , TmpVarPrefix(tmpVarPrefix)
43
0
{
44
0
  this->ActionsPerConfig = true;
45
0
}
46
47
bool cmInstallRuntimeDependencySetGenerator::Compute(cmLocalGenerator* lg)
48
0
{
49
0
  this->LocalGenerator = lg;
50
0
  return true;
51
0
}
52
53
void cmInstallRuntimeDependencySetGenerator::GenerateScriptForConfig(
54
  std::ostream& os, std::string const& config, Indent indent)
55
0
{
56
0
  if (!this->LocalGenerator->GetMakefile()
57
0
         ->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL")
58
0
         .empty() &&
59
0
      !this->NoInstallName) {
60
0
    std::string installNameDir = "@rpath/";
61
0
    if (!this->InstallNameDir.empty()) {
62
0
      installNameDir = this->InstallNameDir;
63
0
      cmGeneratorExpression::ReplaceInstallPrefix(installNameDir,
64
0
                                                  "${CMAKE_INSTALL_PREFIX}");
65
0
      installNameDir = cmGeneratorExpression::Evaluate(
66
0
        installNameDir, this->LocalGenerator, config);
67
0
      if (installNameDir.empty()) {
68
0
        this->LocalGenerator->GetMakefile()->GetCMakeInstance()->IssueMessage(
69
0
          MessageType::FATAL_ERROR,
70
0
          "INSTALL_NAME_DIR argument must not evaluate to an "
71
0
          "empty string",
72
0
          this->Backtrace);
73
0
        return;
74
0
      }
75
0
      if (installNameDir.back() != '/') {
76
0
        installNameDir += '/';
77
0
      }
78
0
    }
79
0
    os << indent << "set(" << this->TmpVarPrefix << "_install_name_dir \""
80
0
       << installNameDir << "\")\n";
81
0
  }
82
83
0
  os << indent << "foreach(" << this->TmpVarPrefix << "_dep IN LISTS "
84
0
     << this->DepsVar << ")\n";
85
86
0
  if (!this->LocalGenerator->GetMakefile()
87
0
         ->GetSafeDefinition("CMAKE_INSTALL_NAME_TOOL")
88
0
         .empty()) {
89
0
    std::vector<std::string> evaluatedRPaths;
90
0
    for (auto const& rpath : this->InstallRPaths) {
91
0
      std::string result =
92
0
        cmGeneratorExpression::Evaluate(rpath, this->LocalGenerator, config);
93
0
      if (!result.empty()) {
94
0
        evaluatedRPaths.push_back(std::move(result));
95
0
      }
96
0
    }
97
98
0
    switch (this->Type) {
99
0
      case DependencyType::Library:
100
0
        this->GenerateAppleLibraryScript(os, config, evaluatedRPaths,
101
0
                                         indent.Next());
102
0
        break;
103
0
      case DependencyType::Framework:
104
0
        this->GenerateAppleFrameworkScript(os, config, evaluatedRPaths,
105
0
                                           indent.Next());
106
0
        break;
107
0
    }
108
0
  } else {
109
0
    std::string depVar = cmStrCat(this->TmpVarPrefix, "_dep");
110
111
0
    this->AddInstallRule(
112
0
      os, this->GetDestination(config), cmInstallType_SHARED_LIBRARY, {},
113
0
      false, this->Permissions.c_str(), nullptr, nullptr,
114
0
      " FOLLOW_SYMLINK_CHAIN", indent.Next(), depVar.c_str());
115
116
0
    if (this->LocalGenerator->GetMakefile()->GetSafeDefinition(
117
0
          "CMAKE_SYSTEM_NAME") == "Linux" &&
118
0
        !this->NoInstallRPath) {
119
0
      std::string evaluatedRPath;
120
0
      for (auto const& rpath : this->InstallRPaths) {
121
0
        std::string result =
122
0
          cmGeneratorExpression::Evaluate(rpath, this->LocalGenerator, config);
123
0
        if (!result.empty()) {
124
0
          if (evaluatedRPath.empty()) {
125
0
            evaluatedRPath = std::move(result);
126
0
          } else {
127
0
            evaluatedRPath += ':';
128
0
            evaluatedRPath += result;
129
0
          }
130
0
        }
131
0
      }
132
133
0
      os << indent.Next() << "get_filename_component(" << this->TmpVarPrefix
134
0
         << "_dep_name \"${" << this->TmpVarPrefix << "_dep}\" NAME)\n";
135
0
      if (evaluatedRPath.empty()) {
136
0
        os << indent.Next() << "file(RPATH_REMOVE FILE \""
137
0
           << GetDestDirPath(
138
0
                ConvertToAbsoluteDestination(this->GetDestination(config)))
139
0
           << "/${" << this->TmpVarPrefix << "_dep_name}\")\n";
140
0
      } else {
141
0
        os << indent.Next() << "file(RPATH_SET FILE \""
142
0
           << GetDestDirPath(
143
0
                ConvertToAbsoluteDestination(this->GetDestination(config)))
144
0
           << "/${" << this->TmpVarPrefix << "_dep_name}\" NEW_RPATH "
145
0
           << cmOutputConverter::EscapeForCMake(evaluatedRPath) << ")\n";
146
0
      }
147
0
    }
148
0
  }
149
150
0
  os << indent << "endforeach()\n";
151
0
}
152
153
void cmInstallRuntimeDependencySetGenerator::GenerateAppleLibraryScript(
154
  std::ostream& os, std::string const& config,
155
  std::vector<std::string> const& evaluatedRPaths, Indent indent)
156
0
{
157
0
  os << indent << "if(NOT " << this->TmpVarPrefix
158
0
     << "_dep MATCHES \"\\\\.framework/\")\n";
159
160
0
  auto depName = cmStrCat(this->TmpVarPrefix, "_dep");
161
0
  this->AddInstallRule(
162
0
    os, this->GetDestination(config), cmInstallType_SHARED_LIBRARY, {}, false,
163
0
    this->Permissions.c_str(), nullptr, nullptr, " FOLLOW_SYMLINK_CHAIN",
164
0
    indent.Next(), depName.c_str());
165
166
0
  os << indent.Next() << "get_filename_component(" << this->TmpVarPrefix
167
0
     << "_dep_name \"${" << this->TmpVarPrefix << "_dep}\" NAME)\n";
168
0
  auto depNameVar = cmStrCat("${", this->TmpVarPrefix, "_dep_name}");
169
0
  this->GenerateInstallNameFixup(os, config, evaluatedRPaths,
170
0
                                 cmStrCat("${", this->TmpVarPrefix, "_dep}"),
171
0
                                 depNameVar, indent.Next());
172
173
0
  os << indent << "endif()\n";
174
0
}
175
176
void cmInstallRuntimeDependencySetGenerator::GenerateAppleFrameworkScript(
177
  std::ostream& os, std::string const& config,
178
  std::vector<std::string> const& evaluatedRPaths, Indent indent)
179
0
{
180
0
  os << indent << "if(" << this->TmpVarPrefix
181
0
     << "_dep MATCHES \"^(.*/)?([^/]*\\\\.framework)/(.*)$\")\n"
182
0
     << indent.Next() << "set(" << this->TmpVarPrefix
183
0
     << "_dir \"${CMAKE_MATCH_1}\")\n"
184
0
     << indent.Next() << "set(" << this->TmpVarPrefix
185
0
     << "_name \"${CMAKE_MATCH_2}\")\n"
186
0
     << indent.Next() << "set(" << this->TmpVarPrefix
187
0
     << "_file \"${CMAKE_MATCH_3}\")\n"
188
0
     << indent.Next() << "set(" << this->TmpVarPrefix << "_path \"${"
189
0
     << this->TmpVarPrefix << "_dir}${" << this->TmpVarPrefix << "_name}\")\n";
190
191
0
  auto depName = cmStrCat(this->TmpVarPrefix, "_path");
192
0
  this->AddInstallRule(
193
0
    os, this->GetDestination(config), cmInstallType_DIRECTORY, {}, false,
194
0
    this->Permissions.c_str(), nullptr, nullptr, " USE_SOURCE_PERMISSIONS",
195
0
    indent.Next(), depName.c_str());
196
197
0
  auto depNameVar = cmStrCat("${", this->TmpVarPrefix, "_name}/${",
198
0
                             this->TmpVarPrefix, "_file}");
199
0
  this->GenerateInstallNameFixup(os, config, evaluatedRPaths,
200
0
                                 cmStrCat("${", this->TmpVarPrefix, "_dep}"),
201
0
                                 depNameVar, indent.Next());
202
203
0
  os << indent << "endif()\n";
204
0
}
205
206
void cmInstallRuntimeDependencySetGenerator::GenerateInstallNameFixup(
207
  std::ostream& os, std::string const& config,
208
  std::vector<std::string> const& evaluatedRPaths, std::string const& filename,
209
  std::string const& depName, Indent indent)
210
0
{
211
0
  if (!(this->NoInstallRPath && this->NoInstallName)) {
212
0
    auto indent2 = indent;
213
0
    if (evaluatedRPaths.empty() && this->NoInstallName) {
214
0
      indent2 = indent2.Next();
215
0
      os << indent << "if(" << this->RPathPrefix << "_" << filename << ")\n";
216
0
    }
217
0
    os << indent2 << "set(" << this->TmpVarPrefix << "_rpath_args)\n";
218
0
    if (!this->NoInstallRPath) {
219
0
      os << indent2 << "foreach(" << this->TmpVarPrefix << "_rpath IN LISTS "
220
0
         << this->RPathPrefix << '_' << filename << ")\n"
221
0
         << indent2.Next() << "list(APPEND " << this->TmpVarPrefix
222
0
         << "_rpath_args -delete_rpath \"${" << this->TmpVarPrefix
223
0
         << "_rpath}\")\n"
224
0
         << indent2 << "endforeach()\n";
225
0
    }
226
0
    os << indent2 << "execute_process(COMMAND \""
227
0
       << this->LocalGenerator->GetMakefile()->GetSafeDefinition(
228
0
            "CMAKE_INSTALL_NAME_TOOL")
229
0
       << "\" ${" << this->TmpVarPrefix << "_rpath_args}\n";
230
0
    if (!this->NoInstallRPath) {
231
0
      for (auto const& rpath : evaluatedRPaths) {
232
0
        os << indent2 << "  -add_rpath "
233
0
           << cmOutputConverter::EscapeForCMake(rpath) << "\n";
234
0
      }
235
0
    }
236
0
    if (!this->NoInstallName) {
237
0
      os << indent2 << "  -id \"${" << this->TmpVarPrefix
238
0
         << "_install_name_dir}" << depName << "\"\n";
239
0
    }
240
0
    os << indent2 << "  \""
241
0
       << GetDestDirPath(
242
0
            ConvertToAbsoluteDestination(this->GetDestination(config)))
243
0
       << "/" << depName << "\")\n";
244
0
    if (evaluatedRPaths.empty() && this->NoInstallName) {
245
0
      os << indent << "endif()\n";
246
0
    }
247
0
  }
248
0
}
249
250
void cmInstallRuntimeDependencySetGenerator::GenerateStripFixup(
251
  std::ostream& os, std::string const& config, std::string const& depName,
252
  Indent indent)
253
0
{
254
0
  std::string strip =
255
0
    this->LocalGenerator->GetMakefile()->GetSafeDefinition("CMAKE_STRIP");
256
0
  if (!strip.empty()) {
257
0
    os << indent << "if(CMAKE_INSTALL_DO_STRIP)\n"
258
0
       << indent.Next() << "execute_process(COMMAND \"" << strip << "\" ";
259
0
    if (this->LocalGenerator->GetMakefile()->IsOn("APPLE")) {
260
0
      os << "-x ";
261
0
    }
262
0
    os << "\""
263
0
       << GetDestDirPath(
264
0
            ConvertToAbsoluteDestination(this->GetDestination(config)))
265
0
       << "/" << depName << "\")\n"
266
0
       << indent << "endif()\n";
267
0
  }
268
0
}
269
270
std::string cmInstallRuntimeDependencySetGenerator::GetDestination(
271
  std::string const& config) const
272
0
{
273
0
  return cmGeneratorExpression::Evaluate(this->Destination,
274
0
                                         this->LocalGenerator, config);
275
0
}