1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt or https://cmake.org/licensing for details.  */
3 #include "cmExportBuildAndroidMKGenerator.h"
4 
5 #include <sstream>
6 #include <utility>
7 
8 #include <cmext/algorithm>
9 
10 #include "cmGeneratorTarget.h"
11 #include "cmLinkItem.h"
12 #include "cmMakefile.h"
13 #include "cmMessageType.h"
14 #include "cmPolicies.h"
15 #include "cmStateTypes.h"
16 #include "cmStringAlgorithms.h"
17 #include "cmSystemTools.h"
18 #include "cmTarget.h"
19 
cmExportBuildAndroidMKGenerator()20 cmExportBuildAndroidMKGenerator::cmExportBuildAndroidMKGenerator()
21 {
22   this->LG = nullptr;
23   this->ExportSet = nullptr;
24 }
25 
GenerateImportHeaderCode(std::ostream & os,const std::string &)26 void cmExportBuildAndroidMKGenerator::GenerateImportHeaderCode(
27   std::ostream& os, const std::string&)
28 {
29   os << "LOCAL_PATH := $(call my-dir)\n\n";
30 }
31 
GenerateImportFooterCode(std::ostream &)32 void cmExportBuildAndroidMKGenerator::GenerateImportFooterCode(std::ostream&)
33 {
34 }
35 
GenerateExpectedTargetsCode(std::ostream &,const std::string &)36 void cmExportBuildAndroidMKGenerator::GenerateExpectedTargetsCode(
37   std::ostream&, const std::string&)
38 {
39 }
40 
GenerateImportTargetCode(std::ostream & os,cmGeneratorTarget const * target,cmStateEnums::TargetType)41 void cmExportBuildAndroidMKGenerator::GenerateImportTargetCode(
42   std::ostream& os, cmGeneratorTarget const* target,
43   cmStateEnums::TargetType /*targetType*/)
44 {
45   std::string targetName = cmStrCat(this->Namespace, target->GetExportName());
46   os << "include $(CLEAR_VARS)\n";
47   os << "LOCAL_MODULE := ";
48   os << targetName << "\n";
49   os << "LOCAL_SRC_FILES := ";
50   std::string const noConfig; // FIXME: What config to use here?
51   std::string path =
52     cmSystemTools::ConvertToOutputPath(target->GetFullPath(noConfig));
53   os << path << "\n";
54 }
55 
GenerateImportPropertyCode(std::ostream &,const std::string &,cmGeneratorTarget const *,ImportPropertyMap const &)56 void cmExportBuildAndroidMKGenerator::GenerateImportPropertyCode(
57   std::ostream&, const std::string&, cmGeneratorTarget const*,
58   ImportPropertyMap const&)
59 {
60 }
61 
GenerateMissingTargetsCheckCode(std::ostream &,const std::vector<std::string> &)62 void cmExportBuildAndroidMKGenerator::GenerateMissingTargetsCheckCode(
63   std::ostream&, const std::vector<std::string>&)
64 {
65 }
66 
GenerateInterfaceProperties(const cmGeneratorTarget * target,std::ostream & os,const ImportPropertyMap & properties)67 void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties(
68   const cmGeneratorTarget* target, std::ostream& os,
69   const ImportPropertyMap& properties)
70 {
71   std::string config;
72   if (!this->Configurations.empty()) {
73     config = this->Configurations[0];
74   }
75   cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties(
76     target, os, properties, cmExportBuildAndroidMKGenerator::BUILD, config);
77 }
78 
GenerateInterfaceProperties(const cmGeneratorTarget * target,std::ostream & os,const ImportPropertyMap & properties,GenerateType type,std::string const & config)79 void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties(
80   const cmGeneratorTarget* target, std::ostream& os,
81   const ImportPropertyMap& properties, GenerateType type,
82   std::string const& config)
83 {
84   const bool newCMP0022Behavior =
85     target->GetPolicyStatusCMP0022() != cmPolicies::WARN &&
86     target->GetPolicyStatusCMP0022() != cmPolicies::OLD;
87   if (!newCMP0022Behavior) {
88     std::ostringstream w;
89     if (type == cmExportBuildAndroidMKGenerator::BUILD) {
90       w << "export(TARGETS ... ANDROID_MK) called with policy CMP0022";
91     } else {
92       w << "install( EXPORT_ANDROID_MK ...) called with policy CMP0022";
93     }
94     w << " set to OLD for target " << target->Target->GetName() << ". "
95       << "The export will only work with CMP0022 set to NEW.";
96     target->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, w.str());
97   }
98   if (!properties.empty()) {
99     os << "LOCAL_CPP_FEATURES := rtti exceptions\n";
100     for (auto const& property : properties) {
101       if (property.first == "INTERFACE_COMPILE_OPTIONS") {
102         os << "LOCAL_CPP_FEATURES += ";
103         os << (property.second) << "\n";
104       } else if (property.first == "INTERFACE_LINK_LIBRARIES") {
105         std::string staticLibs;
106         std::string sharedLibs;
107         std::string ldlibs;
108         cmLinkInterfaceLibraries const* linkIFace =
109           target->GetLinkInterfaceLibraries(config, target, false);
110         for (cmLinkItem const& item : linkIFace->Libraries) {
111           cmGeneratorTarget const* gt = item.Target;
112           std::string const& lib = item.AsStr();
113           if (gt) {
114 
115             if (gt->GetType() == cmStateEnums::SHARED_LIBRARY ||
116                 gt->GetType() == cmStateEnums::MODULE_LIBRARY) {
117               sharedLibs += " " + lib;
118             } else {
119               staticLibs += " " + lib;
120             }
121           } else {
122             bool relpath = false;
123             if (type == cmExportBuildAndroidMKGenerator::INSTALL) {
124               relpath = cmHasLiteralPrefix(lib, "../");
125             }
126             // check for full path or if it already has a -l, or
127             // in the case of an install check for relative paths
128             // if it is full or a link library then use string directly
129             if (cmSystemTools::FileIsFullPath(lib) ||
130                 cmHasLiteralPrefix(lib, "-l") || relpath) {
131               ldlibs += " " + lib;
132               // if it is not a path and does not have a -l then add -l
133             } else if (!lib.empty()) {
134               ldlibs += " -l" + lib;
135             }
136           }
137         }
138         if (!sharedLibs.empty()) {
139           os << "LOCAL_SHARED_LIBRARIES :=" << sharedLibs << "\n";
140         }
141         if (!staticLibs.empty()) {
142           os << "LOCAL_STATIC_LIBRARIES :=" << staticLibs << "\n";
143         }
144         if (!ldlibs.empty()) {
145           os << "LOCAL_EXPORT_LDLIBS :=" << ldlibs << "\n";
146         }
147       } else if (property.first == "INTERFACE_INCLUDE_DIRECTORIES") {
148         std::string includes = property.second;
149         std::vector<std::string> includeList = cmExpandedList(includes);
150         os << "LOCAL_EXPORT_C_INCLUDES := ";
151         std::string end;
152         for (std::string const& i : includeList) {
153           os << end << i;
154           end = "\\\n";
155         }
156         os << "\n";
157       } else if (property.first == "INTERFACE_LINK_OPTIONS") {
158         os << "LOCAL_EXPORT_LDFLAGS := ";
159         std::vector<std::string> linkFlagsList =
160           cmExpandedList(property.second);
161         os << cmJoin(linkFlagsList, " ") << "\n";
162       } else {
163         os << "# " << property.first << " " << (property.second) << "\n";
164       }
165     }
166   }
167 
168   // Tell the NDK build system if prebuilt static libraries use C++.
169   if (target->GetType() == cmStateEnums::STATIC_LIBRARY) {
170     cmLinkImplementation const* li = target->GetLinkImplementation(config);
171     if (cm::contains(li->Languages, "CXX")) {
172       os << "LOCAL_HAS_CPP := true\n";
173     }
174   }
175 
176   switch (target->GetType()) {
177     case cmStateEnums::SHARED_LIBRARY:
178     case cmStateEnums::MODULE_LIBRARY:
179       os << "include $(PREBUILT_SHARED_LIBRARY)\n";
180       break;
181     case cmStateEnums::STATIC_LIBRARY:
182       os << "include $(PREBUILT_STATIC_LIBRARY)\n";
183       break;
184     case cmStateEnums::EXECUTABLE:
185     case cmStateEnums::UTILITY:
186     case cmStateEnums::OBJECT_LIBRARY:
187     case cmStateEnums::GLOBAL_TARGET:
188     case cmStateEnums::INTERFACE_LIBRARY:
189     case cmStateEnums::UNKNOWN_LIBRARY:
190       break;
191   }
192   os << "\n";
193 }
194