Resolve platform specific path at install time
authorWoongsuk Cho <ws77.cho@samsung.com>
Wed, 21 Oct 2020 05:12:26 +0000 (14:12 +0900)
committer조웅석/Common Platform Lab(SR)/Principal Engineer/삼성전자 <ws77.cho@samsung.com>
Fri, 18 Dec 2020 00:54:43 +0000 (09:54 +0900)
If you publish .NET Application without RID designation, it is generated to cross-platform type.
If the .NET application uses a NuGet package that has platform-specific implementations,
all platforms' dependencies are copied to the publish folder along with the app.
(refer to https://docs.microsoft.com/en-us/dotnet/core/deploying)

Libraries and assemblies used for each platform are stored in different locations according to RID and TFM as follows.
(refer to https://natemcmaster.com/blog/2016/05/19/nuget3-rid-graph)

.NET Runtime finds the most suitable paths for its execution environment and uses it by setting APP_PATH and NATIVE_LIBRARY_SEASRCHING_PATH.
These path is set in the coreclr_initializae() function.

Unfortunately, in the case of the candidate process, we cannot specify these kind of paths because a application has not been fixed yet.
So, in the current implementation, all possible combinations of paths are added in priority order.
For this reason, unnecessarily long path settings are being transferred to runtime.

To solve this problem, at the time of installation, I try to change it as if the application was published with the RID setting.
In detail, find the best matched RID and TFM path in the application, and move all contents in them to the "bin" folder.
After then, we can remove runtimes foldr.

The results after resolving are the same as those performed by specifying RID during publish.

NativeLauncher/installer-plugin/delete_unused_library_plugin.cc
NativeLauncher/tool/tac_common.cc
NativeLauncher/util/path_manager.cc

index 1e2fdbd..bd248ac 100644 (file)
@@ -17,7 +17,7 @@
 #include "log.h"
 #include "utils.h"
 
-#include <regex>
+#include <vconf.h>
 #include <vector>
 
 #ifdef  LOG_TAG
@@ -29,6 +29,124 @@ typedef struct _xmlDoc xmlDoc;
 typedef xmlDoc* xmlDocPtr;
 
 bool pluginInstalled = false;
+static const char* __TIZEN_RID_VERSION_KEY = "db/dotnet/tizen_rid_version";
+static const char* __TIZEN_TFM_SUPPORT_KEY = "db/dotnet/tizen_tfm_support";
+
+static std::vector<std::string> getRidFallbackGraph()
+{
+       std::vector<std::string> RID_FALLBACK_GRAPH;
+       char* tizen_rid = vconf_get_str(__TIZEN_RID_VERSION_KEY);
+       if (tizen_rid) {
+               std::vector<std::string> version;
+               splitPath(tizen_rid, version);
+               std::reverse(std::begin(version), std::end(version));
+               for (unsigned int i = 0; i < version.size(); i++) {
+                       RID_FALLBACK_GRAPH.push_back(std::string("tizen." + version[i] + "-" + ARCHITECTURE_IDENTIFIER));
+                       RID_FALLBACK_GRAPH.push_back(std::string("tizen." + version[i]));
+               }
+               free(tizen_rid);
+       }
+
+       std::vector<std::string> RID_FALLBACK_OS = {"tizen", "linux", "unix"};
+       for (unsigned int i = 0; i < RID_FALLBACK_OS.size(); i++) {
+               RID_FALLBACK_GRAPH.push_back(std::string(RID_FALLBACK_OS[i] + "-" + ARCHITECTURE_IDENTIFIER));
+               RID_FALLBACK_GRAPH.push_back(std::string(RID_FALLBACK_OS[i]));
+       }
+       RID_FALLBACK_GRAPH.push_back("any");
+       RID_FALLBACK_GRAPH.push_back("base");
+
+       return RID_FALLBACK_GRAPH;
+}
+
+static std::vector<std::string> getTfmFallbackGraph()
+{
+       std::vector<std::string> tfmList;
+       char* tizen_tfm = vconf_get_str(__TIZEN_TFM_SUPPORT_KEY);
+       if (tizen_tfm) {
+               splitPath(tizen_tfm, tfmList);
+               free(tizen_tfm);
+       }
+
+       return tfmList;
+}
+
+static bool copyAllFilesTo(const std::string& from, const std::string& to)
+{
+       std::vector<std::string> files;
+       try {
+               // make file list to move
+               for (auto& path : bf::recursive_directory_iterator(from)) {
+                       std::string filePath = path.path().string();
+                       if (isFile(filePath)) {
+                               files.push_back(filePath);
+                       }
+               }
+
+               // move files to target directory
+               for (auto& f : files) {
+                       bf::rename(f, concatPath(to, getFileName(f)));
+               }
+       }  catch (const bf::filesystem_error& error) {
+               _ERR("Failed to recursive directory: %s", error.what());
+               return false;
+       }
+
+       return true;
+}
+
+static bool resolvePlatformSpecificFiles(const std::string& appBinPath)
+{
+       std::string runtimesPath = concatPath(appBinPath, "runtimes");
+
+       // if runtimes directory doesnot exist, return true
+       if (!isDirectory(runtimesPath)) {
+               return true;
+       }
+
+       // found best matched rid and tfm directory and copy all files to bin directory
+       std::vector<std::string> ridFallbackGraph = getRidFallbackGraph();
+       for (auto& rid : ridFallbackGraph) {
+               std::string ridPath = concatPath(runtimesPath, rid);
+               if (isDirectory(ridPath)) {
+                       _INFO("Found best matched rid path");
+                       // copy all files from /runtimes/${rid}/native to appBintPath if exist
+                       std::string nativePath = concatPath(ridPath, "native");
+                       if (isDirectory(nativePath)) {
+                               _INFO("Found best matched native path");
+                               if (!copyAllFilesTo(nativePath, appBinPath)) {
+                                       _ERR("Failed to copy files from native path");
+                                       return false;
+                               }
+                       }
+
+                       // found best matched tfm folder in the found rid folder
+                       std::string libPath = concatPath(ridPath, "lib");
+                       std::vector<std::string> tfmFallbackGraph = getTfmFallbackGraph();
+                       for (auto& tfm : tfmFallbackGraph) {
+                               std::string tfmPath = concatPath(libPath, tfm);
+                               if (isDirectory(tfmPath)) {
+                                       _INFO("Found best matched tfm path");
+                                       // copy all files from tfmPath to appBintPath
+                                       if (!copyAllFilesTo(tfmPath, appBinPath)) {
+                                               _ERR("Failed to copy files from tfm path");
+                                               return false;
+                                       }
+                               }
+                       }
+
+                       // finish iteration
+                       break;
+               }
+       }
+
+       // remove runtimes directory
+       if (!removeAll(runtimesPath)) {
+               _ERR("Failed to remove bin/runtimes directory");
+               return false;
+       }
+
+       return true;
+}
 
 extern "C" int PKGMGR_PARSER_PLUGIN_INSTALL(xmlDocPtr doc, const char* pkgId)
 {
@@ -55,36 +173,10 @@ extern "C" int PKGMGR_PARSER_PLUGIN_INSTALL(xmlDocPtr doc, const char* pkgId)
                return 0;
        }
 
-       std::string runtimesDir = concatPath(rootPath, "bin/runtimes");
-       if (!exist(runtimesDir)) {
-               return 0;
-       }
-
-       char buffer[128];
-       sprintf(buffer, "(tizen|linux|unix|base|any)(.\\d.\\d.\\d)?(-%s)?", ARCHITECTURE_IDENTIFIER);
-       std::regex pattern(buffer);
-
-       std::vector<std::string> unusedDir;
-       try {
-               for (auto& path : bf::recursive_directory_iterator(runtimesDir)) {
-                       std::string filepath = path.path().string();
-                       std::string targetDir = filepath.substr(filepath.rfind("/runtimes/") + 10);
-                       if (!std::regex_match(targetDir.substr(0, targetDir.find('/')), pattern)) {
-                               if (isDirectory(filepath)) {
-                                       unusedDir.push_back(filepath);
-                               }
-                       }
-               }
-       } catch (const bf::filesystem_error& error) {
-               _ERR("Failed to recursive directory: %s", error.what());
-       }
-
-       for (auto& path : unusedDir) {
-               if (!removeAll(path)) {
-                       _ERR("Failed to remove of %s", path.c_str());
-               }
+       std::string appBinPath = concatPath(rootPath, "bin");
+       if (!resolvePlatformSpecificFiles(appBinPath)) {
+               _ERR("Failed to resolve platform specific resources of nuget");
        }
-       unusedDir.clear();
 
        return 0;
 }
index 92dbc78..54da934 100644 (file)
@@ -427,8 +427,8 @@ std::vector<std::string> depsJsonParser(const std::string& rootPath, const std::
 std::vector<std::string> getLibrariesInfo(const std::string& rootPath)
 {
        std::vector<std::string> LibrariesInfo;
-       std::string runtimesDir = concatPath(rootPath, "bin/runtimes");
-       if (!exist(runtimesDir))
+       std::string binDir = concatPath(rootPath, "bin");
+       if (!exist(binDir))
                return LibrariesInfo;
 
        auto convert = [&LibrariesInfo](const std::string& filepath, const std::string& filename) {
@@ -438,7 +438,7 @@ std::vector<std::string> getLibrariesInfo(const std::string& rootPath)
                        _INFO("Library : [%s] / SHA256 : [%s]", filename.c_str(), buffer.c_str());
                }
        };
-       scanFilesInDirectory(runtimesDir, convert, -1);
+       scanFilesInDirectory(binDir, convert, -1);
 
        return LibrariesInfo;
 }
index fbd2b3e..ee456f3 100644 (file)
@@ -30,8 +30,6 @@
 #include "log.h"
 
 static const char* __TIZEN_API_PATH_KEY = "db/dotnet/tizen_api_path";
-static const char* __TIZEN_RID_VERSION_KEY = "db/dotnet/tizen_rid_version";
-static const char* __TIZEN_TFM_SUPPORT_KEY = "db/dotnet/tizen_tfm_support";
 
 #define __XSTR(x) #x
 #define __STR(x) __XSTR(x)
@@ -41,53 +39,10 @@ static const char* __NATIVE_LIB_DIR = __STR(NATIVE_LIB_DIR);
 #undef __STR
 #undef __XSTR
 
-// The sequence of RID_FALLBACK graphs must be:
-// 1. Tizen + Version + Architecture
-// 2. Tizen + Version
-// 3. OS(tizen, linux, unix) + Architecture
-// 4. OS(tizen, linux, unix)
-// 5. any, base
-static std::string getRidFallbackGraphDirs(const std::string& appRoot)
-{
-       std::vector<std::string> RID_FALLBACK_GRAPH;
-       char* tizen_rid = vconf_get_str(__TIZEN_RID_VERSION_KEY);
-       if (tizen_rid) {
-               std::vector<std::string> version;
-               splitPath(tizen_rid, version);
-               std::reverse(std::begin(version), std::end(version));
-               for (unsigned int i = 0; i < version.size(); i++) {
-                       RID_FALLBACK_GRAPH.push_back(std::string("tizen." + version[i] + "-" + ARCHITECTURE_IDENTIFIER));
-                       RID_FALLBACK_GRAPH.push_back(std::string("tizen." + version[i]));
-               }
-               free(tizen_rid);
-       }
-
-       std::vector<std::string> RID_FALLBACK_OS = {"tizen", "linux", "unix"};
-       for (unsigned int i = 0; i < RID_FALLBACK_OS.size(); i++) {
-               RID_FALLBACK_GRAPH.push_back(std::string(RID_FALLBACK_OS[i] + "-" + ARCHITECTURE_IDENTIFIER));
-               RID_FALLBACK_GRAPH.push_back(std::string(RID_FALLBACK_OS[i]));
-       }
-       RID_FALLBACK_GRAPH.push_back("any");
-       RID_FALLBACK_GRAPH.push_back("base");
-
-       std::string candidate;
-       for (unsigned int i = 0; i < RID_FALLBACK_GRAPH.size(); i++) {
-               if (!candidate.empty()) {
-                       candidate += ":";
-               }
-               candidate += concatPath(appRoot, "bin/runtimes/" + RID_FALLBACK_GRAPH[i] + "/native");
-       }
-
-       return candidate;
-}
-
-// 1. /appRoot/runtimes/{Platform}-{Architecture}/native/xxxxx.so
-// 2. /appRoot/lib/{Architecture}/xxxxx.so
+// /appRoot/lib/{Architecture}/xxxxx.so
 static std::string getExtraNativeLibDirs(const std::string& appRoot)
 {
-       std::string candidate = getRidFallbackGraphDirs(appRoot);
-
-       candidate = candidate + ":" + concatPath(appRoot, "lib/" ARCHITECTURE_IDENTIFIER);
+       std::string candidate = concatPath(appRoot, "lib/" ARCHITECTURE_IDENTIFIER);
        if (!strncmp(ARCHITECTURE_IDENTIFIER, "arm64", 5)) {
                candidate = candidate + ":" + concatPath(appRoot, "lib/aarch64");
        } else if (!strncmp(ARCHITECTURE_IDENTIFIER, "armel", 5)) {
@@ -97,49 +52,15 @@ static std::string getExtraNativeLibDirs(const std::string& appRoot)
        return candidate;
 }
 
-// 1. /appRoot/runtimes/{Platform}-{Architecture}/lib/{TFMs}/xxxxx.dll
-static std::string getExtraTfmDirs(const std::string& appRoot)
-{
-       std::string candidate;
-       std::vector<std::string> tfmList;
-       char* tizen_tfm = vconf_get_str(__TIZEN_TFM_SUPPORT_KEY);
-       if (tizen_tfm) {
-               splitPath(tizen_tfm, tfmList);
-               free(tizen_tfm);
-       }
-
-       std::vector<std::string> paths;
-       splitPath(replaceAll(getRidFallbackGraphDirs(appRoot), "/native", "/lib"), paths);
-
-       if (tfmList.empty() || paths.empty())
-               return candidate;
-
-       std::vector<std::string> tfmDirectoryList;
-       for (unsigned int i = 0; i < paths.size(); i++) {
-               for (unsigned int j = 0; j < tfmList.size(); j++) {
-                       tfmDirectoryList.push_back(concatPath(paths[i], tfmList[j]));
-               }
-       }
-
-       for (unsigned int i = 0; i < tfmDirectoryList.size(); i++) {
-               if (!candidate.empty()) {
-                       candidate += ":";
-               }
-               candidate += tfmDirectoryList[i];
-       }
-
-       return candidate;
-}
-
 void PathManager::updateAppRelatedPath(const std::string& appRootPath)
 {
        std::string appBinPath = concatPath(appRootPath, "bin");
        std::string appLibPath = concatPath(appRootPath, "lib");
 
        appTacPath = concatPath(appBinPath, TAC_SYMLINK_SUB_DIR);
-       appPaths = appRootPath + ":" + appBinPath + ":" + appLibPath + ":" + appTacPath + ":" + getExtraTfmDirs(appRootPath);
+       appPaths = appRootPath + ":" + appBinPath + ":" + appLibPath + ":" + appTacPath;
        appNIPaths = concatPath(appBinPath, APP_NI_SUB_DIR) + ":" + concatPath(appLibPath, APP_NI_SUB_DIR) + ":"+ appTacPath;
-       nativeDllSearchingPaths = runtimePath + ":" + __NATIVE_LIB_DIR + ":" + getExtraNativeLibDirs(appRootPath) + ":" + appBinPath + ":" + appLibPath;
+       nativeDllSearchingPaths = runtimePath + ":" + __NATIVE_LIB_DIR  + ":" + appBinPath + ":" + appLibPath + ":" + getExtraNativeLibDirs(appRootPath);
 }
 
 PathManager::PathManager() :