Coverage Report

Created: 2026-02-09 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmGeneratorTarget_CompatibleInterface.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
/* clang-format off */
4
#include "cmGeneratorTarget.h"
5
/* clang-format on */
6
7
#include <algorithm>
8
#include <cassert>
9
#include <cerrno>
10
#include <cstddef>
11
#include <cstdlib>
12
#include <cstring>
13
#include <iterator>
14
#include <map>
15
#include <set>
16
#include <sstream>
17
#include <string>
18
#include <utility>
19
#include <vector>
20
21
#include <cm/memory>
22
#include <cmext/algorithm>
23
24
#include "cmComputeLinkInformation.h"
25
#include "cmGeneratorExpression.h"
26
#include "cmList.h"
27
#include "cmLocalGenerator.h"
28
#include "cmMessageType.h"
29
#include "cmRange.h"
30
#include "cmStateTypes.h"
31
#include "cmStringAlgorithms.h"
32
#include "cmSystemTools.h"
33
#include "cmValue.h"
34
35
namespace {
36
using UseTo = cmGeneratorTarget::UseTo;
37
}
38
39
cmGeneratorTarget::CompatibleInterfacesBase const&
40
cmGeneratorTarget::GetCompatibleInterfaces(std::string const& config) const
41
0
{
42
0
  cmGeneratorTarget::CompatibleInterfaces& compat =
43
0
    this->CompatibleInterfacesMap[config];
44
0
  if (!compat.Done) {
45
0
    compat.Done = true;
46
0
    compat.PropsBool.insert("POSITION_INDEPENDENT_CODE");
47
0
    compat.PropsString.insert("AUTOUIC_OPTIONS");
48
0
    std::vector<cmGeneratorTarget const*> const& deps =
49
0
      this->GetLinkImplementationClosure(config, UseTo::Compile);
50
0
    for (cmGeneratorTarget const* li : deps) {
51
0
#define CM_READ_COMPATIBLE_INTERFACE(X, x)                                    \
52
0
  if (cmValue prop = li->GetProperty("COMPATIBLE_INTERFACE_" #X)) {           \
53
0
    cmList props(*prop);                                                      \
54
0
    compat.Props##x.insert(props.begin(), props.end());                       \
55
0
  }
56
0
      CM_READ_COMPATIBLE_INTERFACE(BOOL, Bool)
57
0
      CM_READ_COMPATIBLE_INTERFACE(STRING, String)
58
0
      CM_READ_COMPATIBLE_INTERFACE(NUMBER_MIN, NumberMin)
59
0
      CM_READ_COMPATIBLE_INTERFACE(NUMBER_MAX, NumberMax)
60
0
#undef CM_READ_COMPATIBLE_INTERFACE
61
0
    }
62
0
  }
63
0
  return compat;
64
0
}
65
66
bool cmGeneratorTarget::IsLinkInterfaceDependentBoolProperty(
67
  std::string const& p, std::string const& config) const
68
0
{
69
0
  if (this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
70
0
      this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
71
0
    return false;
72
0
  }
73
0
  return this->GetCompatibleInterfaces(config).PropsBool.count(p) > 0;
74
0
}
75
76
bool cmGeneratorTarget::IsLinkInterfaceDependentStringProperty(
77
  std::string const& p, std::string const& config) const
78
0
{
79
0
  if (this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
80
0
      this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
81
0
    return false;
82
0
  }
83
0
  return this->GetCompatibleInterfaces(config).PropsString.count(p) > 0;
84
0
}
85
86
bool cmGeneratorTarget::IsLinkInterfaceDependentNumberMinProperty(
87
  std::string const& p, std::string const& config) const
88
0
{
89
0
  if (this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
90
0
      this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
91
0
    return false;
92
0
  }
93
0
  return this->GetCompatibleInterfaces(config).PropsNumberMin.count(p) > 0;
94
0
}
95
96
bool cmGeneratorTarget::IsLinkInterfaceDependentNumberMaxProperty(
97
  std::string const& p, std::string const& config) const
98
0
{
99
0
  if (this->GetType() == cmStateEnums::OBJECT_LIBRARY ||
100
0
      this->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
101
0
    return false;
102
0
  }
103
0
  return this->GetCompatibleInterfaces(config).PropsNumberMax.count(p) > 0;
104
0
}
105
106
enum CompatibleType
107
{
108
  BoolType,
109
  StringType,
110
  NumberMinType,
111
  NumberMaxType
112
};
113
114
template <typename PropertyType>
115
PropertyType getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
116
                                               std::string const& prop,
117
                                               std::string const& config,
118
                                               CompatibleType, PropertyType*);
119
120
template <>
121
bool getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
122
                                       std::string const& prop,
123
                                       std::string const& config,
124
                                       CompatibleType /*unused*/,
125
                                       bool* /*unused*/)
126
0
{
127
0
  return tgt->GetLinkInterfaceDependentBoolProperty(prop, config);
128
0
}
129
130
template <>
131
char const* getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
132
                                              std::string const& prop,
133
                                              std::string const& config,
134
                                              CompatibleType t,
135
                                              char const** /*unused*/)
136
0
{
137
0
  switch (t) {
138
0
    case BoolType:
139
0
      assert(false &&
140
0
             "String compatibility check function called for boolean");
141
0
      return nullptr;
142
0
    case StringType:
143
0
      return tgt->GetLinkInterfaceDependentStringProperty(prop, config);
144
0
    case NumberMinType:
145
0
      return tgt->GetLinkInterfaceDependentNumberMinProperty(prop, config);
146
0
    case NumberMaxType:
147
0
      return tgt->GetLinkInterfaceDependentNumberMaxProperty(prop, config);
148
0
  }
149
0
  assert(false && "Unreachable!");
150
0
  return nullptr;
151
0
}
152
153
template <typename PropertyType>
154
void checkPropertyConsistency(cmGeneratorTarget const* depender,
155
                              cmGeneratorTarget const* dependee,
156
                              std::string const& propName,
157
                              std::set<std::string>& emitted,
158
                              std::string const& config, CompatibleType t,
159
                              PropertyType* /*unused*/)
160
0
{
161
0
  cmValue prop = dependee->GetProperty(propName);
162
0
  if (!prop) {
163
0
    return;
164
0
  }
165
166
0
  cmList props{ *prop };
167
0
  std::string pdir =
168
0
    cmStrCat(cmSystemTools::GetCMakeRoot(), "/Help/prop_tgt/");
169
170
0
  for (std::string const& p : props) {
171
0
    std::string pname = cmSystemTools::HelpFileName(p);
172
0
    std::string pfile = cmStrCat(pdir, pname, ".rst");
173
0
    if (cmSystemTools::FileExists(pfile, true)) {
174
0
      std::ostringstream e;
175
0
      e << "Target \"" << dependee->GetName() << "\" has property \"" << p
176
0
        << "\" listed in its " << propName
177
0
        << " property.  "
178
0
           "This is not allowed.  Only user-defined properties may appear "
179
0
           "listed in the "
180
0
        << propName << " property.";
181
0
      depender->GetLocalGenerator()->IssueMessage(MessageType::FATAL_ERROR,
182
0
                                                  e.str());
183
0
      return;
184
0
    }
185
0
    if (emitted.insert(p).second) {
186
0
      getLinkInterfaceDependentProperty<PropertyType>(depender, p, config, t,
187
0
                                                      nullptr);
188
0
      if (cmSystemTools::GetErrorOccurredFlag()) {
189
0
        return;
190
0
      }
191
0
    }
192
0
  }
193
0
}
Unexecuted instantiation: void checkPropertyConsistency<bool>(cmGeneratorTarget const*, cmGeneratorTarget const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::set<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, CompatibleType, bool*)
Unexecuted instantiation: void checkPropertyConsistency<char const*>(cmGeneratorTarget const*, cmGeneratorTarget const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::set<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, CompatibleType, char const**)
194
195
namespace {
196
std::string intersect(std::set<std::string> const& s1,
197
                      std::set<std::string> const& s2)
198
0
{
199
0
  std::set<std::string> intersect;
200
0
  std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(),
201
0
                        std::inserter(intersect, intersect.begin()));
202
0
  if (!intersect.empty()) {
203
0
    return *intersect.begin();
204
0
  }
205
0
  return "";
206
0
}
207
208
std::string intersect(std::set<std::string> const& s1,
209
                      std::set<std::string> const& s2,
210
                      std::set<std::string> const& s3)
211
0
{
212
0
  std::string result;
213
0
  result = intersect(s1, s2);
214
0
  if (!result.empty()) {
215
0
    return result;
216
0
  }
217
0
  result = intersect(s1, s3);
218
0
  if (!result.empty()) {
219
0
    return result;
220
0
  }
221
0
  return intersect(s2, s3);
222
0
}
223
224
std::string intersect(std::set<std::string> const& s1,
225
                      std::set<std::string> const& s2,
226
                      std::set<std::string> const& s3,
227
                      std::set<std::string> const& s4)
228
0
{
229
0
  std::string result;
230
0
  result = intersect(s1, s2);
231
0
  if (!result.empty()) {
232
0
    return result;
233
0
  }
234
0
  result = intersect(s1, s3);
235
0
  if (!result.empty()) {
236
0
    return result;
237
0
  }
238
0
  result = intersect(s1, s4);
239
0
  if (!result.empty()) {
240
0
    return result;
241
0
  }
242
0
  return intersect(s2, s3, s4);
243
0
}
244
}
245
246
void cmGeneratorTarget::CheckPropertyCompatibility(
247
  cmComputeLinkInformation& info, std::string const& config) const
248
0
{
249
0
  cmComputeLinkInformation::ItemVector const& deps = info.GetItems();
250
251
0
  std::set<std::string> emittedBools;
252
0
  static std::string const strBool = "COMPATIBLE_INTERFACE_BOOL";
253
0
  std::set<std::string> emittedStrings;
254
0
  static std::string const strString = "COMPATIBLE_INTERFACE_STRING";
255
0
  std::set<std::string> emittedMinNumbers;
256
0
  static std::string const strNumMin = "COMPATIBLE_INTERFACE_NUMBER_MIN";
257
0
  std::set<std::string> emittedMaxNumbers;
258
0
  static std::string const strNumMax = "COMPATIBLE_INTERFACE_NUMBER_MAX";
259
260
0
  for (auto const& dep : deps) {
261
0
    if (!dep.Target || dep.Target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
262
0
      continue;
263
0
    }
264
265
0
    checkPropertyConsistency<bool>(this, dep.Target, strBool, emittedBools,
266
0
                                   config, BoolType, nullptr);
267
0
    if (cmSystemTools::GetErrorOccurredFlag()) {
268
0
      return;
269
0
    }
270
0
    checkPropertyConsistency<char const*>(this, dep.Target, strString,
271
0
                                          emittedStrings, config, StringType,
272
0
                                          nullptr);
273
0
    if (cmSystemTools::GetErrorOccurredFlag()) {
274
0
      return;
275
0
    }
276
0
    checkPropertyConsistency<char const*>(this, dep.Target, strNumMin,
277
0
                                          emittedMinNumbers, config,
278
0
                                          NumberMinType, nullptr);
279
0
    if (cmSystemTools::GetErrorOccurredFlag()) {
280
0
      return;
281
0
    }
282
0
    checkPropertyConsistency<char const*>(this, dep.Target, strNumMax,
283
0
                                          emittedMaxNumbers, config,
284
0
                                          NumberMaxType, nullptr);
285
0
    if (cmSystemTools::GetErrorOccurredFlag()) {
286
0
      return;
287
0
    }
288
0
  }
289
290
0
  std::string prop = intersect(emittedBools, emittedStrings, emittedMinNumbers,
291
0
                               emittedMaxNumbers);
292
293
0
  if (!prop.empty()) {
294
    // Use a sorted std::vector to keep the error message sorted.
295
0
    std::vector<std::string> props;
296
0
    auto i = emittedBools.find(prop);
297
0
    if (i != emittedBools.end()) {
298
0
      props.push_back(strBool);
299
0
    }
300
0
    i = emittedStrings.find(prop);
301
0
    if (i != emittedStrings.end()) {
302
0
      props.push_back(strString);
303
0
    }
304
0
    i = emittedMinNumbers.find(prop);
305
0
    if (i != emittedMinNumbers.end()) {
306
0
      props.push_back(strNumMin);
307
0
    }
308
0
    i = emittedMaxNumbers.find(prop);
309
0
    if (i != emittedMaxNumbers.end()) {
310
0
      props.push_back(strNumMax);
311
0
    }
312
0
    std::sort(props.begin(), props.end());
313
314
0
    std::string propsString = cmStrCat(
315
0
      cmJoin(cmMakeRange(props).retreat(1), ", "), " and the ", props.back());
316
317
0
    std::ostringstream e;
318
0
    e << "Property \"" << prop << "\" appears in both the " << propsString
319
0
      << " property in the dependencies of target \"" << this->GetName()
320
0
      << "\".  This is not allowed. A property may only require "
321
0
         "compatibility "
322
0
         "in a boolean interpretation, a numeric minimum, a numeric maximum "
323
0
         "or a "
324
0
         "string interpretation, but not a mixture.";
325
0
    this->LocalGenerator->IssueMessage(MessageType::FATAL_ERROR, e.str());
326
0
  }
327
0
}
328
329
template <typename PropertyType>
330
std::string valueAsString(PropertyType);
331
template <>
332
std::string valueAsString<bool>(bool value)
333
0
{
334
0
  return value ? "TRUE" : "FALSE";
335
0
}
336
template <>
337
std::string valueAsString<char const*>(char const* value)
338
0
{
339
0
  return value ? value : "(unset)";
340
0
}
341
template <>
342
std::string valueAsString<std::string>(std::string value)
343
0
{
344
0
  return value;
345
0
}
346
template <>
347
std::string valueAsString<cmValue>(cmValue value)
348
0
{
349
0
  return value ? *value : std::string("(unset)");
350
0
}
351
template <>
352
std::string valueAsString<std::nullptr_t>(std::nullptr_t /*unused*/)
353
0
{
354
0
  return "(unset)";
355
0
}
356
357
static std::string compatibilityType(CompatibleType t)
358
0
{
359
0
  switch (t) {
360
0
    case BoolType:
361
0
      return "Boolean compatibility";
362
0
    case StringType:
363
0
      return "String compatibility";
364
0
    case NumberMaxType:
365
0
      return "Numeric maximum compatibility";
366
0
    case NumberMinType:
367
0
      return "Numeric minimum compatibility";
368
0
  }
369
0
  assert(false && "Unreachable!");
370
0
  return "";
371
0
}
372
373
static std::string compatibilityAgree(CompatibleType t, bool dominant)
374
0
{
375
0
  switch (t) {
376
0
    case BoolType:
377
0
    case StringType:
378
0
      return dominant ? "(Disagree)\n" : "(Agree)\n";
379
0
    case NumberMaxType:
380
0
    case NumberMinType:
381
0
      return dominant ? "(Dominant)\n" : "(Ignored)\n";
382
0
  }
383
0
  assert(false && "Unreachable!");
384
0
  return "";
385
0
}
386
387
template <typename PropertyType>
388
PropertyType getTypedProperty(
389
  cmGeneratorTarget const* tgt, std::string const& prop,
390
  cmGeneratorExpressionInterpreter* genexInterpreter = nullptr);
391
392
template <>
393
bool getTypedProperty<bool>(cmGeneratorTarget const* tgt,
394
                            std::string const& prop,
395
                            cmGeneratorExpressionInterpreter* genexInterpreter)
396
0
{
397
0
  if (!genexInterpreter) {
398
0
    return tgt->GetPropertyAsBool(prop);
399
0
  }
400
401
0
  cmValue value = tgt->GetProperty(prop);
402
0
  return cmIsOn(genexInterpreter->Evaluate(value ? *value : "", prop));
403
0
}
404
405
template <>
406
char const* getTypedProperty<char const*>(
407
  cmGeneratorTarget const* tgt, std::string const& prop,
408
  cmGeneratorExpressionInterpreter* genexInterpreter)
409
0
{
410
0
  cmValue value = tgt->GetProperty(prop);
411
412
0
  if (!genexInterpreter) {
413
0
    return value.GetCStr();
414
0
  }
415
416
0
  return genexInterpreter->Evaluate(value ? *value : "", prop).c_str();
417
0
}
418
419
template <>
420
std::string getTypedProperty<std::string>(
421
  cmGeneratorTarget const* tgt, std::string const& prop,
422
  cmGeneratorExpressionInterpreter* genexInterpreter)
423
0
{
424
0
  cmValue value = tgt->GetProperty(prop);
425
426
0
  if (!genexInterpreter) {
427
0
    return valueAsString(value);
428
0
  }
429
430
0
  return genexInterpreter->Evaluate(value ? *value : "", prop);
431
0
}
432
433
template <typename PropertyType>
434
PropertyType impliedValue(PropertyType);
435
template <>
436
bool impliedValue<bool>(bool /*unused*/)
437
0
{
438
0
  return false;
439
0
}
440
template <>
441
char const* impliedValue<char const*>(char const* /*unused*/)
442
0
{
443
0
  return "";
444
0
}
445
template <>
446
std::string impliedValue<std::string>(std::string /*unused*/) // NOLINT(*)
447
0
{
448
0
  return std::string();
449
0
}
450
451
template <typename PropertyType>
452
std::pair<bool, PropertyType> consistentProperty(PropertyType lhs,
453
                                                 PropertyType rhs,
454
                                                 CompatibleType t);
455
456
template <>
457
std::pair<bool, bool> consistentProperty(bool lhs, bool rhs,
458
                                         CompatibleType /*unused*/)
459
0
{
460
0
  return { lhs == rhs, lhs };
461
0
}
462
463
static std::pair<bool, char const*> consistentStringProperty(char const* lhs,
464
                                                             char const* rhs)
465
0
{
466
0
  bool const b = strcmp(lhs, rhs) == 0;
467
0
  return { b, b ? lhs : nullptr };
468
0
}
469
470
static std::pair<bool, std::string> consistentStringProperty(
471
  std::string const& lhs, std::string const& rhs)
472
0
{
473
0
  bool const b = lhs == rhs;
474
0
  return { b, b ? lhs : valueAsString(nullptr) };
475
0
}
476
477
static std::pair<bool, char const*> consistentNumberProperty(char const* lhs,
478
                                                             char const* rhs,
479
                                                             CompatibleType t)
480
0
{
481
0
  char* pEnd;
482
483
0
  long lnum = strtol(lhs, &pEnd, 0);
484
0
  if (pEnd == lhs || *pEnd != '\0' || errno == ERANGE) {
485
0
    return { false, nullptr };
486
0
  }
487
488
0
  long rnum = strtol(rhs, &pEnd, 0);
489
0
  if (pEnd == rhs || *pEnd != '\0' || errno == ERANGE) {
490
0
    return { false, nullptr };
491
0
  }
492
493
0
  if (t == NumberMaxType) {
494
0
    return { true, std::max(lnum, rnum) == lnum ? lhs : rhs };
495
0
  }
496
497
0
  return { true, std::min(lnum, rnum) == lnum ? lhs : rhs };
498
0
}
499
500
template <>
501
std::pair<bool, char const*> consistentProperty(char const* lhs,
502
                                                char const* rhs,
503
                                                CompatibleType t)
504
0
{
505
0
  if (!lhs && !rhs) {
506
0
    return { true, lhs };
507
0
  }
508
0
  if (!lhs) {
509
0
    return { true, rhs };
510
0
  }
511
0
  if (!rhs) {
512
0
    return { true, lhs };
513
0
  }
514
515
0
  switch (t) {
516
0
    case BoolType: {
517
0
      bool same = cmIsOn(lhs) == cmIsOn(rhs);
518
0
      return { same, same ? lhs : nullptr };
519
0
    }
520
0
    case StringType:
521
0
      return consistentStringProperty(lhs, rhs);
522
0
    case NumberMinType:
523
0
    case NumberMaxType:
524
0
      return consistentNumberProperty(lhs, rhs, t);
525
0
  }
526
0
  assert(false && "Unreachable!");
527
0
  return { false, nullptr };
528
0
}
529
530
static std::pair<bool, std::string> consistentProperty(std::string const& lhs,
531
                                                       std::string const& rhs,
532
                                                       CompatibleType t)
533
0
{
534
0
  std::string const null_ptr = valueAsString(nullptr);
535
536
0
  if (lhs == null_ptr && rhs == null_ptr) {
537
0
    return { true, lhs };
538
0
  }
539
0
  if (lhs == null_ptr) {
540
0
    return { true, rhs };
541
0
  }
542
0
  if (rhs == null_ptr) {
543
0
    return { true, lhs };
544
0
  }
545
546
0
  switch (t) {
547
0
    case BoolType: {
548
0
      bool same = cmIsOn(lhs) == cmIsOn(rhs);
549
0
      return { same, same ? lhs : null_ptr };
550
0
    }
551
0
    case StringType:
552
0
      return consistentStringProperty(lhs, rhs);
553
0
    case NumberMinType:
554
0
    case NumberMaxType: {
555
0
      auto value = consistentNumberProperty(lhs.c_str(), rhs.c_str(), t);
556
0
      return { value.first,
557
0
               value.first ? std::string(value.second) : null_ptr };
558
0
    }
559
0
  }
560
0
  assert(false && "Unreachable!");
561
0
  return { false, null_ptr };
562
0
}
563
564
template <typename PropertyType>
565
PropertyType checkInterfacePropertyCompatibility(cmGeneratorTarget const* tgt,
566
                                                 std::string const& p,
567
                                                 std::string const& config,
568
                                                 char const* defaultValue,
569
                                                 CompatibleType t,
570
                                                 PropertyType* /*unused*/)
571
0
{
572
0
  PropertyType propContent = getTypedProperty<PropertyType>(tgt, p);
573
574
0
  std::vector<std::string> headPropKeys = tgt->GetPropertyKeys();
575
0
  bool const explicitlySet = cm::contains(headPropKeys, p);
576
577
0
  bool const impliedByUse = tgt->IsNullImpliedByLinkLibraries(p);
578
0
  assert((impliedByUse ^ explicitlySet) || (!impliedByUse && !explicitlySet));
579
580
0
  std::vector<cmGeneratorTarget const*> const& deps =
581
0
    tgt->GetLinkImplementationClosure(config, UseTo::Compile);
582
583
0
  if (deps.empty()) {
584
0
    return propContent;
585
0
  }
586
0
  bool propInitialized = explicitlySet;
587
588
0
  std::string report = cmStrCat(" * Target \"", tgt->GetName());
589
0
  if (explicitlySet) {
590
0
    report += "\" has property content \"";
591
0
    report += valueAsString<PropertyType>(propContent);
592
0
    report += "\"\n";
593
0
  } else if (impliedByUse) {
594
0
    report += "\" property is implied by use.\n";
595
0
  } else {
596
0
    report += "\" property not set.\n";
597
0
  }
598
599
0
  std::string interfaceProperty = "INTERFACE_" + p;
600
0
  std::unique_ptr<cmGeneratorExpressionInterpreter> genexInterpreter;
601
0
  if (p == "POSITION_INDEPENDENT_CODE") {
602
    // Corresponds to EvaluatingPICExpression.
603
0
    genexInterpreter = cm::make_unique<cmGeneratorExpressionInterpreter>(
604
0
      tgt->GetLocalGenerator(), config, tgt);
605
0
  }
606
607
0
  for (cmGeneratorTarget const* theTarget : deps) {
608
    // An error should be reported if one dependency
609
    // has INTERFACE_POSITION_INDEPENDENT_CODE ON and the other
610
    // has INTERFACE_POSITION_INDEPENDENT_CODE OFF, or if the
611
    // target itself has a POSITION_INDEPENDENT_CODE which disagrees
612
    // with a dependency.
613
614
0
    std::vector<std::string> propKeys = theTarget->GetPropertyKeys();
615
616
0
    bool const ifaceIsSet = cm::contains(propKeys, interfaceProperty);
617
0
    PropertyType ifacePropContent = getTypedProperty<PropertyType>(
618
0
      theTarget, interfaceProperty, genexInterpreter.get());
619
620
0
    std::string reportEntry;
621
0
    if (ifaceIsSet) {
622
0
      reportEntry += " * Target \"";
623
0
      reportEntry += theTarget->GetName();
624
0
      reportEntry += "\" property value \"";
625
0
      reportEntry += valueAsString<PropertyType>(ifacePropContent);
626
0
      reportEntry += "\" ";
627
0
    }
628
629
0
    if (explicitlySet) {
630
0
      if (ifaceIsSet) {
631
0
        std::pair<bool, PropertyType> consistent =
632
0
          consistentProperty(propContent, ifacePropContent, t);
633
0
        report += reportEntry;
634
0
        report += compatibilityAgree(t, propContent != consistent.second);
635
0
        if (!consistent.first) {
636
0
          std::ostringstream e;
637
0
          e << "Property " << p << " on target \"" << tgt->GetName()
638
0
            << "\" does\nnot match the "
639
0
               "INTERFACE_"
640
0
            << p
641
0
            << " property requirement\nof "
642
0
               "dependency \""
643
0
            << theTarget->GetName() << "\".\n";
644
0
          cmSystemTools::Error(e.str());
645
0
          break;
646
0
        }
647
0
        propContent = consistent.second;
648
0
        continue;
649
0
      }
650
      // Explicitly set on target and not set in iface. Can't disagree.
651
0
      continue;
652
0
    }
653
0
    if (impliedByUse) {
654
0
      propContent = impliedValue<PropertyType>(propContent);
655
656
0
      if (ifaceIsSet) {
657
0
        std::pair<bool, PropertyType> consistent =
658
0
          consistentProperty(propContent, ifacePropContent, t);
659
0
        report += reportEntry;
660
0
        report += compatibilityAgree(t, propContent != consistent.second);
661
0
        if (!consistent.first) {
662
0
          std::ostringstream e;
663
0
          e << "Property " << p << " on target \"" << tgt->GetName()
664
0
            << "\" is\nimplied to be " << defaultValue
665
0
            << " because it was used to determine the link libraries\n"
666
0
               "already. The INTERFACE_"
667
0
            << p << " property on\ndependency \"" << theTarget->GetName()
668
0
            << "\" is in conflict.\n";
669
0
          cmSystemTools::Error(e.str());
670
0
          break;
671
0
        }
672
0
        propContent = consistent.second;
673
0
        continue;
674
0
      }
675
      // Implicitly set on target and not set in iface. Can't disagree.
676
0
      continue;
677
0
    }
678
0
    if (ifaceIsSet) {
679
0
      if (propInitialized) {
680
0
        std::pair<bool, PropertyType> consistent =
681
0
          consistentProperty(propContent, ifacePropContent, t);
682
0
        report =
683
0
          cmStrCat(std::move(report), reportEntry,
684
0
                   compatibilityAgree(t, propContent != consistent.second));
685
0
        if (!consistent.first) {
686
0
          std::ostringstream e;
687
0
          e << "The INTERFACE_" << p << " property of \""
688
0
            << theTarget->GetName() << "\" does\nnot agree with the value of "
689
0
            << p << " already determined\nfor \"" << tgt->GetName() << "\".\n";
690
0
          cmSystemTools::Error(e.str());
691
0
          break;
692
0
        }
693
0
        propContent = consistent.second;
694
0
        continue;
695
0
      }
696
0
      report = cmStrCat(std::move(report), reportEntry, "(Interface set)\n");
697
0
      propContent = ifacePropContent;
698
0
      propInitialized = true;
699
0
    } else {
700
      // Not set. Nothing to agree on.
701
0
      continue;
702
0
    }
703
0
  }
704
705
0
  tgt->ReportPropertyOrigin(p, valueAsString<PropertyType>(propContent),
706
0
                            report, compatibilityType(t));
707
0
  return propContent;
708
0
}
Unexecuted instantiation: bool checkInterfacePropertyCompatibility<bool>(cmGeneratorTarget const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const*, CompatibleType, bool*)
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > checkInterfacePropertyCompatibility<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(cmGeneratorTarget const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const*, CompatibleType, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*)
Unexecuted instantiation: char const* checkInterfacePropertyCompatibility<char const*>(cmGeneratorTarget const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const*, CompatibleType, char const**)
709
710
bool cmGeneratorTarget::GetLinkInterfaceDependentBoolProperty(
711
  std::string const& p, std::string const& config) const
712
0
{
713
0
  return checkInterfacePropertyCompatibility<bool>(this, p, config, "FALSE",
714
0
                                                   BoolType, nullptr);
715
0
}
716
717
std::string cmGeneratorTarget::GetLinkInterfaceDependentStringAsBoolProperty(
718
  std::string const& p, std::string const& config) const
719
0
{
720
0
  return checkInterfacePropertyCompatibility<std::string>(
721
0
    this, p, config, "FALSE", BoolType, nullptr);
722
0
}
723
724
char const* cmGeneratorTarget::GetLinkInterfaceDependentStringProperty(
725
  std::string const& p, std::string const& config) const
726
0
{
727
0
  return checkInterfacePropertyCompatibility<char const*>(
728
0
    this, p, config, "empty", StringType, nullptr);
729
0
}
730
731
char const* cmGeneratorTarget::GetLinkInterfaceDependentNumberMinProperty(
732
  std::string const& p, std::string const& config) const
733
0
{
734
0
  return checkInterfacePropertyCompatibility<char const*>(
735
0
    this, p, config, "empty", NumberMinType, nullptr);
736
0
}
737
738
char const* cmGeneratorTarget::GetLinkInterfaceDependentNumberMaxProperty(
739
  std::string const& p, std::string const& config) const
740
0
{
741
0
  return checkInterfacePropertyCompatibility<char const*>(
742
0
    this, p, config, "empty", NumberMaxType, nullptr);
743
0
}