Coverage Report

Created: 2026-03-12 06:35

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