Modified to support crossgen2 (#330)
author조웅석/Common Platform Lab(SR)/Principal Engineer/삼성전자 <ws77.cho@samsung.com>
Thu, 9 Sep 2021 06:34:53 +0000 (15:34 +0900)
committerGitHub Enterprise <noreply-CODE@samsung.com>
Thu, 9 Sep 2021 06:34:53 +0000 (15:34 +0900)
* support crossgen2

add --crossgen2 and --inputbubble option
By vconf setting, crossgen2 can be used from prefer_dotnet_aot_plugin.

* support crossgen2

add --crossgen2 and --inputbubble option
By vconf setting, crossgen2 can be used from prefer_dotnet_aot_plugin.

NativeLauncher/inc/ni_common.h
NativeLauncher/installer-plugin/prefer_dotnet_aot_plugin.cc
NativeLauncher/tool/dotnettool.cc
NativeLauncher/tool/ni_common.cc
dotnet-launcher.manifest
packaging/dotnet-launcher.spec
tests/TCs/6_TOOL/TOOL.py
tests/TCs/Utils.py

index d12b4b2..989e199 100644 (file)
 #define NI_FLAGS_COMPATIBILITY          0x0004
 #define NI_FLAGS_VERBOSE                0x0008
 #define NI_FLAGS_APP_UNDER_RO_AREA      0x0010
+#define NI_FLAGS_USE_CROSSGEN2          0x0100
+#define NI_FLAGS_INPUT_BUBBLE           0x0200
+#define NI_FLAGS_INPUT_BUBBLE_REF       0x0400
+#define NI_FLAGS_NO_PIPELINE            0x0800
 #define NI_FLAGS_INSTRUMENT             0x1000
 
 typedef std::function<void (std::string)> afterCreate;
index 6f93e44..57b2182 100644 (file)
@@ -17,6 +17,7 @@
 #include "ni_common.h"
 #include "log.h"
 #include "utils.h"
+#include <vconf.h>
 
 #include <cstring>
 #include <vector>
@@ -62,7 +63,8 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_INSTALL(const char *pkgId, const char *app
                        return -1;
                }
 
-               if (createNIUnderPkgRoot(pkgId, 0) != NI_ERROR_NONE) {
+               DWORD flags = 0;
+               if (createNIUnderPkgRoot(pkgId, flags) != NI_ERROR_NONE) {
                        _ERR("Failed to generate application to native image [%s]", pkgId);
                        return -1;
                }
index dc3cfcf..b6f51c8 100644 (file)
@@ -61,6 +61,10 @@ void DisplayUsage() {
                "                                   (replaces /r with /Trusted_Platform_Assemblies)\n"
                "       --verbose                 - Display verbose information\n"
                "       --instrument              - Generate an instrumented image for profiling (enable: /Tuning)\n"
+               "       --crossgen2               - Use crossgen2\n"
+               "       --inputbubble             - Use inputbubble (run with --crossgen2 option)\n"
+               "       --no-pipeline             - Compile the dlls individually (run with --crossgen2 option)\n"
+
                "\n"
                "Usage: dotnettool [options] [command] [arguments]\n"
                "\n"
@@ -111,6 +115,12 @@ int main(int argc, char* argv[])
                        flags |= NI_FLAGS_INSTRUMENT;
                } else if (!strncmp(*it, "--verbose", 9)) {
                        flags |= NI_FLAGS_VERBOSE;
+               } else if (!strncmp(*it, "--crossgen2", 11)) {
+                       flags |= NI_FLAGS_USE_CROSSGEN2;
+               } else if (!strncmp(*it, "--inputbubble", 13)) {
+                       flags |= NI_FLAGS_INPUT_BUBBLE;
+               } else if (!strncmp(*it, "--no-pipeline", 13)) {
+                       flags |= NI_FLAGS_NO_PIPELINE;
                } else {
                        args.push_back(*it);
                }
index e2e9f4d..23e9ec5 100644 (file)
@@ -71,9 +71,62 @@ static const char* __SYSTEM_BASE_FILE = __STR(SYSTEM_BASE_FILE);
 #undef __STR
 #undef __XSTR
 
+static const char* CORERUN_CMD = "/usr/bin/dotnet-inhouse";
+static const char* CROSSGEN2_PATH = "/usr/share/dotnet.tizen/netcoreapp/crossgen2/crossgen2.dll";
+static const char* CLRJIT_PATH = "/usr/share/dotnet.tizen/netcoreapp/libclrjit.so";
+static const char* CROSSGEN_OPT_JITPATH = "--jitpath";
+static const char* CROSSGEN_OPT_TARGET_ARCH = "--targetarch";
+static const char* CROSSGEN_OPT_OUT_NEAR_INPUT = "--out-near-input";
+static const char* CROSSGEN_OPT_SINGLE_FILE_COMPILATION = "--single-file-compilation";
+//static const char* CROSSGEN_OPT_PARALLELISM = "--parallelism";
+//static const char* CROSSGEN_OPT_PARALLELISM_COUNT = "5";
+static const char* CROSSGEN_OPT_RESILIENT = "--resilient";
+static const char* CROSSGEN_OPT_OPTIMIZE = "-O";
+static const char* CROSSGEN_OPT_INPUTBUBBLE = "--inputbubble";
+static const char* CROSSGEN_OPT_COMPILE_BUBBLE_GENERICS = "--compilebubblegenerics";
+static const char* CROSSGEN_OPT_VERBOSE = "--verbose";
+static const char* CROSSGEN_OPT_TUNING = "--tuning";
+static std::vector<std::string> REF_VECTOR;
+
 static int __interval = 0;
 static PathManager* __pm = nullptr;
 
+static bool isCoreLibPrepared(DWORD flags)
+{
+       if (flags & NI_FLAGS_ENABLER2R) {
+               return true;
+       }
+
+       std::string coreLibBackup = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll.Backup");
+       if (isFile(coreLibBackup)) {
+               return true;
+       } else {
+               _SERR("The native image of System.Private.CoreLib does not exist\n"
+                                       "Run the command to create the native image\n"
+                                       "# dotnettool --ni-dll /usr/share/dotnet.tizen/netcoreapp/System.Private.CoreLib.dll\n");
+               return false;
+       }
+}
+
+static bool hasCoreLibNI()
+{
+       std::string ildasm = concatPath(__pm->getRuntimePath(), "ildasm");
+       std::string coreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll");
+       std::string cmd = ildasm + " " + coreLib + " -noil -stats | grep '.rsrc'";
+
+       FILE *fp;
+       fp = popen(cmd.c_str(), "r");
+       if (fp != NULL) {
+               char buff[1024];
+               if (fgets(buff, sizeof(buff), fp) != NULL) {
+                       pclose(fp);
+                       return false;
+               }
+               pclose(fp);
+       }
+       return true;
+}
+
 static void waitInterval()
 {
        // by the recommand, ignore small value for performance.
@@ -165,8 +218,9 @@ static std::string getAppNIFilePath(const std::string& absDllPath, DWORD flags)
        return getNIFilePath(concatPath(niDirPath, getFileName(absDllPath)));
 }
 
-static bool checkNIExistence(const std::string& absDllPath, const std::string& absNIPath)
+static bool checkNIExistence(const std::string& absDllPath)
 {
+       std::string absNIPath = getNIFilePath(absDllPath);
        if (absNIPath.empty()) {
                return false;
        }
@@ -178,8 +232,7 @@ static bool checkNIExistence(const std::string& absDllPath, const std::string& a
        // native image of System.Private.CoreLib.dll should have to overwrite
        // original file to support new coreclr
        if (absDllPath.find("System.Private.CoreLib.dll") != std::string::npos) {
-               std::string coreLibBackup = absDllPath + ".Backup";
-               if (isFile(coreLibBackup)) {
+               if (hasCoreLibNI()) {
                        return true;
                }
        }
@@ -187,6 +240,46 @@ static bool checkNIExistence(const std::string& absDllPath, const std::string& a
        return false;
 }
 
+static bool checkDllExistInDir(const std::string& path)
+{
+       bool ret = false;
+       auto func = [&ret](const std::string& f_path, const std::string& f_name) {
+               if (isManagedAssembly(f_name) || isNativeImage(f_name)) {
+                       ret = true;
+               }
+       };
+
+       scanFilesInDirectory(path, func, 0);
+
+       return ret;
+}
+
+/*
+ * Get the list of managed files in the specific directory
+ * Absolute paths of managed files are stored at the result list.
+ * If native image already exist in the same directory, managed file is ignored.
+ *
+ * Note: System.Private.CoreLib is excluded from the result list.
+ */
+static ni_error_e getTargetDllList(const std::string& path, std::vector<std::string>& fileList)
+{
+       if (!isDirectory(path)) {
+               return NI_ERROR_INVALID_PARAMETER;
+       }
+
+       auto func = [&fileList](const std::string& f_path, const std::string& f_name) {
+               if (isManagedAssembly(f_path) && !checkNIExistence(f_path)) {
+                       if (f_path.find("System.Private.CoreLib") == std::string::npos) {
+                               fileList.push_back(getAbsolutePath(f_path));
+                       }
+               }
+       };
+
+       scanFilesInDirectory(path, func, 0);
+
+       return NI_ERROR_NONE;
+}
+
 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
 static uintptr_t getFileSize(const std::string& path)
 {
@@ -278,24 +371,20 @@ static bool isTPADll(const std::string& dllPath)
 // baseAddr should be checked in file before getting here
 static ni_error_e crossgen(const std::string& dllPath, const std::string& appPath, DWORD flags)
 {
-       if (!isFile(dllPath)) {
-               _SERR("dll file is not exist : %s", dllPath.c_str());
-               return NI_ERROR_NO_SUCH_FILE;
-       }
-
-       if (!isManagedAssembly(dllPath)) {
-               //_SERR("Input file is not a dll file : %s", dllPath.c_str());
-               return NI_ERROR_INVALID_PARAMETER;
-       }
-
        std::string absDllPath = getAbsolutePath(dllPath);
        std::string absNIPath;
 
        bool isAppNI = flags & NI_FLAGS_APPNI;
        if (isAppNI && strstr(absDllPath.c_str(), __DOTNET_DIR) == NULL) {
                absNIPath = getAppNIFilePath(absDllPath, flags);
+               if (exist(absNIPath)) {
+                       return NI_ERROR_ALREADY_EXIST;
+               }
        } else {
                absNIPath = getNIFilePath(absDllPath);
+               if (checkNIExistence(absDllPath)) {
+                       return NI_ERROR_ALREADY_EXIST;
+               }
        }
 
        if (absNIPath.empty()) {
@@ -303,11 +392,6 @@ static ni_error_e crossgen(const std::string& dllPath, const std::string& appPat
                return NI_ERROR_UNKNOWN;
        }
 
-       if (checkNIExistence(absDllPath, absNIPath)) {
-               //_SERR("Already ni file is exist for %s", absNIPath.c_str());
-               return NI_ERROR_ALREADY_EXIST;
-       }
-
 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
        uintptr_t baseAddr = 0;
 
@@ -416,6 +500,256 @@ static ni_error_e crossgen(const std::string& dllPath, const std::string& appPat
        return NI_ERROR_NONE;
 }
 
+static void makeArgs(std::vector<const char*>& args, const std::vector<std::string>& refPaths, DWORD flags)
+{
+       args.push_back(CORERUN_CMD);
+       args.push_back(CROSSGEN2_PATH);
+       args.push_back(CROSSGEN_OPT_JITPATH);
+       args.push_back(CLRJIT_PATH);
+       args.push_back(CROSSGEN_OPT_TARGET_ARCH);
+       args.push_back(ARCHITECTURE_IDENTIFIER);
+       if (!(flags & NI_FLAGS_NO_PIPELINE)) {
+               args.push_back(CROSSGEN_OPT_OUT_NEAR_INPUT);
+               args.push_back(CROSSGEN_OPT_SINGLE_FILE_COMPILATION);
+       }
+       //args.push_back(OPT_PARALLELISM);
+       //args.push_back(OPT_PARALLELISM_COUNT);
+       args.push_back(CROSSGEN_OPT_RESILIENT);
+
+       args.push_back(CROSSGEN_OPT_OPTIMIZE);
+
+       if (flags & NI_FLAGS_INPUT_BUBBLE) {
+               args.push_back(CROSSGEN_OPT_INPUTBUBBLE);
+               args.push_back(CROSSGEN_OPT_COMPILE_BUBBLE_GENERICS);
+       }
+
+       if (flags & NI_FLAGS_VERBOSE) {
+               args.push_back(CROSSGEN_OPT_VERBOSE);
+       }
+
+       if (flags & NI_FLAGS_INSTRUMENT) {
+               args.push_back(CROSSGEN_OPT_TUNING);
+       }
+
+       REF_VECTOR.clear();
+
+       // set reference path
+       std::vector<std::string> paths = __pm->getPlatformAssembliesPaths();
+       for (const auto &path : paths) {
+               REF_VECTOR.push_back("-r:" + path + "/*.dll");
+       }
+
+       for (const auto &path : refPaths) {
+               if (checkDllExistInDir(path)) {
+                       REF_VECTOR.push_back("-r:" + path + "/*.dll");
+               }
+       }
+
+       for (const auto &path : REF_VECTOR) {
+               args.push_back(path.c_str());
+       }
+}
+
+static void clearArgs(std::vector<const char*>& args)
+{
+       REF_VECTOR.clear();
+       args.clear();
+}
+
+static ni_error_e makePdbSymlinkForNI(std::string dllPath, std::string niPath)
+{
+       std::string pdbPath = changeExtension(dllPath, ".dll", ".pdb");
+       try {
+               if (exist(pdbPath)) {
+                       std::string targetPDBPath = changeExtension(niPath, ".ni.dll", ".pdb");
+                       if (!exist(targetPDBPath)) {
+                               bf::create_symlink(pdbPath, targetPDBPath);
+                               copySmackAndOwnership(pdbPath, targetPDBPath, true);
+                       }
+               }
+       } catch (const bf::filesystem_error& error) {
+               _SERR("Fail to create symlink for %s", pdbPath.c_str());
+               return NI_ERROR_UNKNOWN;
+       }
+
+       return NI_ERROR_NONE;
+}
+
+static ni_error_e crossgen2PipeLine(const std::vector<std::string>& dllList, const std::vector<std::string>& refPaths, DWORD flags)
+{
+       // fork crossgen2
+       pid_t pid = fork();
+       if (pid == -1)
+               return NI_ERROR_UNKNOWN;
+
+       if (pid > 0) {
+               int status;
+               waitpid(pid, &status, 0);
+               if (WIFEXITED(status)) {
+                       for (auto& dllPath: dllList) {
+                               std::string niPath = changeExtension(dllPath, ".dll", ".ni.dll");
+
+                               if (!exist(niPath)) {
+                                       _SERR("Fail to create native image for %s", dllPath.c_str());
+                                       return NI_ERROR_NO_SUCH_FILE;
+                               }
+
+                               copySmackAndOwnership(dllPath, niPath);
+                               // if AppNI then move ni.dll file to .native_image and copy pdb to .native_image
+                               if (flags & NI_FLAGS_APPNI) {
+                                       std::string appNIPath = getAppNIFilePath(dllPath, flags);
+                                       moveFile(niPath, appNIPath);
+                                       makePdbSymlinkForNI(dllPath, appNIPath);
+                                       niPath = appNIPath;
+                               }
+                               _SOUT("Native image %s generated successfully.", niPath.c_str());
+                       }
+               }
+       } else {
+               std::vector<const char*> argv;
+
+               makeArgs(argv, refPaths, flags);
+
+               // add input files at the end of parameter
+               for (const auto &input : dllList) {
+                       argv.push_back(input.c_str());
+                       _SOUT("+ %s", input.c_str());
+               }
+
+               argv.push_back(nullptr);
+
+               // print cmd
+               //for (auto &arg: argv) _SOUT("+ %s", arg);
+
+               execv(CORERUN_CMD, const_cast<char* const*>(argv.data()));
+
+               clearArgs(argv);
+               exit(0);
+       }
+
+       return NI_ERROR_NONE;
+}
+
+static ni_error_e crossgen2NoPipeLine(const std::vector<std::string>& dllList, const std::vector<std::string>& refPaths, DWORD flags)
+{
+       for (auto& dllPath : dllList) {
+               std::string niPath;
+               if (flags & NI_FLAGS_APPNI) {
+                       niPath = getAppNIFilePath(dllPath, flags);
+               } else {
+                       niPath = getNIFilePath(dllPath);
+               }
+
+               // fork crossgen2
+               pid_t pid = fork();
+               if (pid == -1)
+                       return NI_ERROR_UNKNOWN;
+
+               if (pid > 0) {
+                       int status;
+                       waitpid(pid, &status, 0);
+                       if (WIFEXITED(status)) {
+                               if (!exist(niPath)) {
+                                       _SERR("Fail to create native image for %s", dllPath.c_str());
+                                       return NI_ERROR_NO_SUCH_FILE;
+                               }
+
+                               copySmackAndOwnership(dllPath, niPath);
+                               if (flags & NI_FLAGS_APPNI) {
+                                       makePdbSymlinkForNI(dllPath, niPath);
+                               }
+                               _SOUT("Native image %s generated successfully.", niPath.c_str());
+                       }
+               } else {
+                       std::vector<const char*> argv;
+                       makeArgs(argv, refPaths, flags);
+
+                       argv.push_back("-o");
+                       argv.push_back(niPath.c_str());
+
+                       argv.push_back(dllPath.c_str());
+                       _SOUT("+ %s", dllPath.c_str());
+
+                       // end param
+                       argv.push_back(nullptr);
+
+                       // print cmd
+                       //for (auto &arg: argv) _SOUT("+ %s", arg);
+
+                       execv(CORERUN_CMD, const_cast<char* const*>(argv.data()));
+
+                       clearArgs(argv);
+                       exit(0);
+               }
+
+               waitInterval();
+       }
+
+       return NI_ERROR_NONE;
+}
+
+
+static ni_error_e doAOTList(std::vector<std::string>& dllList, const std::string& refPaths, DWORD flags)
+{
+       if (dllList.empty()) {
+               return NI_ERROR_INVALID_PARAMETER;
+       }
+       // When performing AOT for one Dll, an error is returned when an error occurs.
+       // However, when processing multiple dlls at once, only the log for errors is output and skipped.
+
+       for (auto it = dllList.begin(); it != dllList.end(); it++) {
+               std::string f = *it;
+               if (!isFile(f)) {
+                       _SERR("dll file is not exist : %s", f.c_str());
+                       dllList.erase(it--);
+               }
+               if (!isManagedAssembly(f)) {
+                       _SERR("Input file is not a dll file : %s", f.c_str());
+                       dllList.erase(it--);
+               }
+       }
+
+       if (!isFile(concatPath(__pm->getRuntimePath(), "crossgen"))) {
+               _SERR("crossgen1 doesnot supported. use crossgen2 forcibily");
+               flags |= NI_FLAGS_USE_CROSSGEN2;
+       }
+
+       if (flags & NI_FLAGS_USE_CROSSGEN2) {           // crossgen2
+               std::vector<std::string> paths;
+               splitPath(refPaths, paths);
+
+               if (flags & NI_FLAGS_NO_PIPELINE) {
+                       crossgen2NoPipeLine(dllList, paths, flags);
+               } else {
+                       crossgen2PipeLine(dllList, paths, flags);
+               }
+       } else {                                                                        // crossgen1
+               for (auto& dll : dllList) {
+                       crossgen(dll, refPaths, flags);
+                       waitInterval();
+               }
+       }
+
+       return NI_ERROR_NONE;
+}
+
+static ni_error_e doAOTFile(const std::string& dllFile, const std::string& refPaths, DWORD flags)
+{
+       if (!isFile(dllFile)) {
+               _SERR("dll file is not exist : %s", dllFile.c_str());
+               return NI_ERROR_NO_SUCH_FILE;
+       }
+
+       if (!isManagedAssembly(dllFile)) {
+               _SERR("Failed. Input parameter is not managed dll (%s)\n", dllFile.c_str());
+               return NI_ERROR_INVALID_PARAMETER;
+       }
+
+       std::vector<std::string> dllList;
+       dllList.push_back(getAbsolutePath(dllFile));
+       return doAOTList(dllList, refPaths, flags);
+}
+
 // callback function of "pkgmgrinfo_appinfo_metadata_filter_foreach"
 static int appAotCb(pkgmgrinfo_appinfo_h handle, void *userData)
 {
@@ -444,42 +778,6 @@ static int appAotCb(pkgmgrinfo_appinfo_h handle, void *userData)
        return 0;
 }
 
-static bool isCoreLibPrepared(DWORD flags)
-{
-       if (flags & NI_FLAGS_ENABLER2R) {
-               return true;
-       }
-
-       std::string coreLibBackup = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll.Backup");
-       if (isFile(coreLibBackup)) {
-               return true;
-       } else {
-               _SERR("The native image of System.Private.CoreLib does not exist\n"
-                                       "Run the command to create the native image\n"
-                                       "# dotnettool --ni-dll /usr/share/dotnet.tizen/netcoreapp/System.Private.CoreLib.dll\n");
-               return false;
-       }
-}
-
-static bool hasCoreLibNI()
-{
-       std::string ildasm = concatPath(__pm->getRuntimePath(), "ildasm");
-       std::string coreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll");
-       std::string cmd = ildasm + " " + coreLib + " -noil -stats | grep '\\.xdata'";
-
-       FILE *fp;
-       fp = popen(cmd.c_str(), "r");
-       if (fp != NULL) {
-               char buff[1024];
-               if (fgets(buff, sizeof(buff), fp) != NULL) {
-                       pclose(fp);
-                       return true;
-               }
-               pclose(fp);
-       }
-       return false;
-}
-
 static ni_error_e createCoreLibNI(DWORD flags)
 {
        std::string coreLib = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll");
@@ -487,7 +785,7 @@ static ni_error_e createCoreLibNI(DWORD flags)
        std::string coreLibBackup = concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll.Backup");
 
        if (!isFile(coreLibBackup) && !hasCoreLibNI()) {
-               if (!crossgen(coreLib, std::string(), flags)) {
+               if (doAOTFile(coreLib, std::string(), flags) == NI_ERROR_NONE) {
                        if (rename(coreLib.c_str(), coreLibBackup.c_str())) {
                                _SERR("Failed to rename System.Private.CoreLib.dll");
                                return NI_ERROR_CORE_NI_FILE;
@@ -556,8 +854,9 @@ void finalizeNICommon()
 
 ni_error_e createNIPlatform(DWORD flags)
 {
-       if (createCoreLibNI(flags) != NI_ERROR_NONE) {
-               return NI_ERROR_CORE_NI_FILE;
+       ni_error_e ret = createCoreLibNI(flags);
+       if (ret != NI_ERROR_NONE) {
+               return ret;
        }
 
        return createNIUnderDirs(__pm->getRuntimePath() + ":" + __pm->getTizenFXPath(), flags);
@@ -573,71 +872,91 @@ ni_error_e createNIDll(const std::string& dllPath, DWORD flags)
                return NI_ERROR_CORE_NI_FILE;
        }
 
-       return crossgen(dllPath, std::string(), flags);
+       return doAOTFile(dllPath, std::string(), flags);
 }
 
-ni_error_e createNIUnderDirs(const std::string& rootPaths, DWORD flags)
+ni_error_e createNIUnderTAC(const std::string& targetPath, const std::string& refPaths, DWORD flags)
 {
-       if (!isCoreLibPrepared(flags)) {
-               return NI_ERROR_CORE_NI_FILE;
+       ni_error_e ret;
+
+       // get managed file list from targetPath
+       std::vector<std::string> dllList;
+       ret = getTargetDllList(targetPath, dllList);
+       if (ret != NI_ERROR_NONE) {
+               return ret;
        }
 
-       auto convert = [&rootPaths, flags](const std::string& path, const std::string& filename) {
-               // if path is symlink, donot generate crossgen
-               if (!crossgen(path, rootPaths.c_str(), flags)) {
-                       waitInterval();
+       std::vector<std::string> needNIList;
+       std::vector<std::string> niList;
+
+       for (auto &dll : dllList) {
+               if (!checkNIExistence(dll)) {
+                       needNIList.push_back(dll);
                }
-       };
+               niList.push_back(getNIFilePath(dll));
+       }
 
-       std::vector<std::string> targetPaths;
-       splitPath(rootPaths, targetPaths);
-       for (const auto &path : targetPaths) {
-               // TAC directory should be handled specially because that contains symlink of native image file.
-               if (strstr(path.c_str(), TAC_SYMLINK_SUB_DIR) != NULL) {
-                       if (!isDirectory(path)) {
-                               continue;
+       if (!needNIList.empty()) {
+               // NI fils of TAC-related dlls under /opt/usr/dotnet should not be created under .native_image directory.
+               // So, unset NI_FLAGS_APPNI temporally and restore it after running AOT.
+               flags &= ~NI_FLAGS_APPNI;
+               ret = doAOTList(needNIList, refPaths, flags);
+               flags |= NI_FLAGS_APPNI;
+               if (ret != NI_ERROR_NONE) {
+                       return ret;
+               }
+       }
+
+       for (auto &niPath : niList) {
+               if (exist(niPath)) {
+                       std::string symNIPath = concatPath(targetPath, getFileName(niPath));
+                       if (!exist(symNIPath)) {
+                               bf::create_symlink(niPath, symNIPath);
+                               copySmackAndOwnership(targetPath.c_str(), symNIPath.c_str(), true);
+                               _SOUT("%s symbolic link file generated successfully.", symNIPath.c_str());
+                               _INFO("%s symbolic link file generated successfully.", symNIPath.c_str());
                        }
-                       // make native image symlink if not exist under tac directory
-                       try {
-                               for (auto& symlinkAssembly : bf::recursive_directory_iterator(path)) {
-                                       std::string symPath = symlinkAssembly.path().string();
-                                       if (!isManagedAssembly(symPath)) {
-                                               continue;
-                                       }
+               }
+       }
 
-                                       // if there is symlink and original file for native image, skip generation
-                                       std::string symNIPath = changeExtension(symPath, "dll", "ni.dll");
-                                       if (isFile(symNIPath)) {
-                                               continue;
-                                       }
+       return NI_ERROR_NONE;
+}
 
-                                       // if original native image not exist, generate native image
-                                       std::string originPath = bf::read_symlink(symPath).string();
-                                       std::string originNIPath = changeExtension(originPath, "dll", "ni.dll");
-                                       if (!isFile(originNIPath)) {
-                                               if (!crossgen(originPath, path.c_str(), flags)) {
-                                                       waitInterval();
-                                               }
-                                       }
 
-                                       // if no symlink file exist, create symlink
-                                       if (!isFile(symNIPath)) {
-                                               bf::create_symlink(originNIPath, symNIPath);
-                                               copySmackAndOwnership(symPath.c_str(), symNIPath.c_str(), true);
-                                               _SOUT("%s symbolic link file generated successfully.", symNIPath.c_str());
-                                               _INFO("%s symbolic link file generated successfully.", symNIPath.c_str());
-                                       }
-                               }
-                       } catch (const bf::filesystem_error& error) {
-                               _SERR("Failed to recursive directory: %s", error.what());
-                               return NI_ERROR_UNKNOWN;
+ni_error_e createNIUnderDirs(const std::string& rootPaths, DWORD flags)
+{
+       ni_error_e ret = NI_ERROR_NONE;
+       if (!isCoreLibPrepared(flags)) {
+               return NI_ERROR_CORE_NI_FILE;
+       }
+
+       std::vector<std::string> fileList;
+       std::vector<std::string> paths;
+       splitPath(rootPaths, paths);
+
+       for (const auto &path : paths) {
+               if (!exist(path)) {
+                       continue;
+               }
+
+               if (path.find(TAC_SYMLINK_SUB_DIR) != std::string::npos) {
+                       ret = createNIUnderTAC(path, rootPaths, flags);
+                       if (ret != NI_ERROR_NONE) {
+                               return ret;
                        }
                } else {
-                       scanFilesInDirectory(path, convert, 0);
+                       ret = getTargetDllList(path, fileList);
+                       if (ret != NI_ERROR_NONE) {
+                               return ret;
+                       }
                }
        }
 
-       return NI_ERROR_NONE;
+       if (fileList.empty()) {
+               return NI_ERROR_NONE;
+       }
+
+       return doAOTList(fileList, rootPaths, flags);
 }
 
 ni_error_e createNIUnderPkgRoot(const std::string& pkgId, DWORD flags)
@@ -654,6 +973,8 @@ ni_error_e createNIUnderPkgRoot(const std::string& pkgId, DWORD flags)
 
        if (isReadOnlyArea(rootPath)) {
                flags |= NI_FLAGS_APP_UNDER_RO_AREA;
+               flags |= NI_FLAGS_NO_PIPELINE;
+               _SERR("Only no-pipeline mode supported for RO app. Set no-pipeline option forcibly");
        } else {
                flags &= ~NI_FLAGS_APP_UNDER_RO_AREA;
        }
@@ -738,6 +1059,16 @@ ni_error_e removeNIUnderPkgRoot(const std::string& pkgId)
                }
        }
 
+       // In special cases, the ni file may exist in the dll location.
+       // The code below is to avoid this exceptional case.
+       std::string appPaths = __pm->getAppPaths();
+       splitPath(appPaths, paths);
+       for (const auto &path : paths) {
+               if (isDirectory(path)) {
+                       removeNIUnderDirs(path);
+               }
+       }
+
        return NI_ERROR_NONE;
 }
 
@@ -806,16 +1137,8 @@ static int regenTacCb(pkgmgrinfo_appinfo_h handle, void *userData)
                nugetPaths += concatPath(__DOTNET_DIR, nuget);
        }
 
-       auto convert = [&nugetPaths, pFlags](const std::string& path, const std::string& filename) {
-               if (strstr(path.c_str(), TAC_SHA_256_INFO) != NULL)
-                       return;
-               if (!crossgen(path, nugetPaths.c_str(), *pFlags)) {
-                       waitInterval();
-               }
-       };
-
        for (auto& nuget : nugets) {
-               scanFilesInDirectory(concatPath(__DOTNET_DIR, nuget), convert, -1);
+               createNIUnderTAC(concatPath(__DOTNET_DIR, nuget), nugetPaths, *pFlags);
        }
 
        return 0;
index 71d0ad6..05c7b6b 100644 (file)
@@ -7,5 +7,6 @@
         <filesystem path="/opt/usr/dotnet/apps" label="User::Home"/>
         <filesystem path="/usr/bin/dotnet-loader" label="User" exec_label="User" />
         <filesystem path="/usr/bin/dotnet" label="System::Tools" exec_label="User" />
+        <filesystem path="/usr/bin/dotnet-inhouse" label="System" exec_label="System" />
     </assign>
 </manifest>
index e4dd257..cc6d8f5 100644 (file)
@@ -173,6 +173,9 @@ mv packaging/10.Dotnet.Launcher.preload %{buildroot}%{_tizen_preload_dir}
 # for gbs-support
 cp -a %{buildroot}%{_bindir}/dotnet %{buildroot}%{_bindir}/dotnet-corerun
 
+# for crossgen2-support
+cp -a %{buildroot}%{_bindir}/dotnet %{buildroot}%{_bindir}/dotnet-inhouse
+
 # to support fota upgrade
 mkdir -p %{buildroot}/%{_rw_update_scripts_dir}
 install -m 0755 packaging/%{_rw_dotnet_update_script} %{buildroot}/%{_rw_update_scripts_dir}/%{_rw_dotnet_update_script}
@@ -200,6 +203,7 @@ chsmack -a User /usr/bin/dotnet-nui-loader
 %{_bindir}/dotnet-launcher
 %{_bindir}/dotnet-loader
 %{_bindir}/dotnet
+%{_bindir}/dotnet-inhouse
 %{_bindir}/dotnet-hydra-loader
 %{_libdir}/libdotnet_launcher_util.so
 %{_libdir}/libdotnet_launcher_core.so
index 8635f0f..7629d7a 100755 (executable)
@@ -22,15 +22,15 @@ def TC_01():
 
 # The `native image` is generated normally.
 def TC_02():
-    cmd(f"shell dotnettool --ni-system")
+    cmd(f"shell dotnettool {CROSSGEN2_OPTION} --ni-system")
 
     if not exist(f"{RUNTIME_DIR}{SPC_DLL}.Backup"):
         return "FAIL : Create the platform native image"
 
     raw = cmd(f"shell find {RUNTIME_DIR} -name *.ni.dll")
     lines1 = [l for l in raw.splitlines()]
-    len1 = len(lines1) + 2 # System.Private.CoreLib.dll, System.Runtime.WindowsRuntime.dll
-    raw = cmd(f"shell find {RUNTIME_DIR} -name *.dll -not -name *.ni.dll")
+    len1 = len(lines1) + 1 # System.Private.CoreLib.dll
+    raw = cmd(f"shell find {RUNTIME_DIR} -maxdepth 1 -name *.dll -not -name *.ni.dll")
     lines2 = [l for l in raw.splitlines()]
     len2 = len(lines2)
     if len1 != len2:
@@ -58,7 +58,7 @@ def TC_02():
 
 # Remove the `platform` native image.
 def TC_03():
-    cmd(f"shell dotnettool --ni-reset-system")
+    cmd(f"shell dotnettool {CROSSGEN2_OPTION} --ni-reset-system")
 
     if exist(f"{RUNTIME_DIR}{SPC_DLL}.Backup"):
         return "FAIL : Remove the platform native image"
@@ -71,8 +71,8 @@ def TC_04():
         cmd(f"shell rm {RUNTIME_DIR}{SPC_DLL}")
         cmd(f"shell mv {RUNTIME_DIR}{SPC_DLL}.Backup {RUNTIME_DIR}{SPC_DLL}")
 
-    raw = cmd(f"shell dotnettool --ni-dll {RUNTIME_DIR}{SPC_DLL}")
-    if (f"{SPC_DLL} (FNV)" not in raw) or \
+    raw = cmd(f"shell dotnettool {CROSSGEN2_OPTION} --ni-dll {RUNTIME_DIR}{SPC_DLL}")
+    if (f"{SPC_DLL}" not in raw) or \
        ("System.Private.CoreLib.ni.dll generated successfully." not in raw):
         return f"FAIL : Create native image for {SPC_DLL}"
 
@@ -83,7 +83,7 @@ def TC_04():
 
 # The file name of `.dll` and `.ni.dll` must match in the framework.
 def TC_05():
-    cmd(f"shell dotnettool --ni-dir {FRAMEWORK_DIR}")
+    cmd(f"shell dotnettool {CROSSGEN2_OPTION} --ni-dir {FRAMEWORK_DIR}")
     raw = cmd(f"shell find {FRAMEWORK_DIR} -name *.ni.dll")
     lines1 = [l for l in raw.splitlines()]
     raw = cmd(f"shell find {FRAMEWORK_DIR} -name *.dll -not -name *.ni.dll")
@@ -114,8 +114,8 @@ def TC_06():
 
 # Create native image for Tizen.dll in `R2R` mode.
 def TC_07():
-    raw = cmd(f"shell dotnettool --r2r --ni-dll {FRAMEWORK_DIR}Tizen.dll")
-    if ("Tizen.dll (R2R)" not in raw) or \
+    raw = cmd(f"shell dotnettool {CROSSGEN2_OPTION} --r2r --ni-dll {FRAMEWORK_DIR}Tizen.dll")
+    if ("Tizen.dll" not in raw) or \
        ("Tizen.ni.dll generated successfully." not in raw):
         return "FAIL : Create native image for Tizen.dll in R2R mode"
 
@@ -123,10 +123,8 @@ def TC_07():
 
 # Displays detailed information while creating native image for Tizen.Log.dll.
 def TC_08():
-    raw = cmd(f"shell dotnettool --verbose --ni-dll {FRAMEWORK_DIR}Tizen.Log.dll")
-    if ("Opening input file" not in raw) or \
-       ("Breakdown of Indirections" not in raw) or \
-       ("Tizen.Log.ni.dll generated successfully." not in raw):
+    raw = cmd(f"shell dotnettool {CROSSGEN2_OPTION} --verbose --ni-dll {FRAMEWORK_DIR}Tizen.Log.dll")
+    if ("Tizen.Log.ni.dll generated successfully." not in raw):
         return "FAIL : Displays detailed information while creating native image for Tizen.Log.dll"
 
     return "PASS"
@@ -152,8 +150,8 @@ def TC_09():
     if not exist(f"{IBCDATA_DIR}netstandard.ibc"):
         return "FAIL : The netstandard.ibc file should exist"
 
-    raw = cmd(f"shell dotnettool --ibc-dir /usr/share/dotnet.tizen/ibcdata/ --ni-dll {RUNTIME_DIR}netstandard.dll")
-    if ("netstandard.dll (FNV)" not in raw) or \
+    raw = cmd(f"shell dotnettool {CROSSGEN2_OPTION} --ibc-dir /usr/share/dotnet.tizen/ibcdata/ --ni-dll {RUNTIME_DIR}netstandard.dll")
+    if ("netstandard.dll" not in raw) or \
        ("netstandard.ni.dll generated successfully." not in raw):
         return "FAIL : Create native image for netstandard.dll"
 
@@ -211,7 +209,7 @@ def TC_11():
     if exist(f"{root_path}/bin/.native_image"):
         return "FAIL : The .native_image folder not should exist"
 
-    cmd(f"shell dotnettool --ni-pkg {pkg_id}")
+    cmd(f"shell dotnettool {CROSSGEN2_OPTION} --ni-pkg {pkg_id}")
 
     if not exist(f"{root_path}/bin/.native_image"):
         return "FAIL : The .native_image folder should exist"
@@ -245,7 +243,7 @@ def TC_12():
     if "OK" not in app_install(f"{tpk_path}"):
         return f"FAIL : Install the application for {tpk_path}"
 
-    cmd(f"shell dotnettool --ni-regen-all-app")
+    cmd(f"shell dotnettool {CROSSGEN2_OPTION} --ni-regen-all-app")
 
     raw = subprocess.run((f"sdb -s {serial} shell pkginfo --metadata-flt").split(), stdout=subprocess.PIPE, input=f"http://tizen.org/metadata/prefer_dotnet_aot\ntrue\n", encoding="utf-8").stdout
     lines = [l for l in raw.splitlines() if "appid" in l]
@@ -285,8 +283,8 @@ def TC_13():
     if "OK" not in app_install(f"{tpk_path}"):
         return f"FAIL : Install the application for {tpk_path}"
 
-    raw = cmd(f"shell dotnettool --tac-regen-all")
-    if (".dll (FNV)" not in raw) or \
+    raw = cmd(f"shell dotnettool {CROSSGEN2_OPTION} --tac-regen-all")
+    if (".dll" not in raw) or \
        (".ni.dll generated successfully." not in raw):
         return "FAIL : Create native image for TAC"
 
@@ -439,7 +437,7 @@ def TC_17():
 
     cmd(f"shell mount -o remount,ro /")
 
-    cmd(f"shell dotnettool --ni-regen-all-app")
+    cmd(f"shell dotnettool {CROSSGEN2_OPTION} --ni-regen-all-app")
 
     raw = subprocess.run((f"sdb -s {serial} shell pkginfo --metadata-flt").split(), stdout=subprocess.PIPE, input=f"http://tizen.org/metadata/prefer_dotnet_aot\ntrue\n", encoding="utf-8").stdout
     lines = [l for l in raw.splitlines() if "appid" in l]
@@ -521,7 +519,7 @@ def TC_19():
     if exist(f"{root_path}/bin/.native_image"):
         return "FAIL : The .native_image folder not should exist"
 
-    cmd(f"shell dotnettool --ni-pkg {pkg_id}")
+    cmd(f"shell dotnettool {CROSSGEN2_OPTION} --ni-pkg {pkg_id}")
 
     if not exist(f"{DOTNET_DIR}apps/{pkg_id}/bin/.native_image"):
         return "FAIL : The .native_image folder should exist"
index 0a25754..03928b6 100755 (executable)
@@ -13,6 +13,7 @@ IBCDATA_DIR = "/usr/share/dotnet.tizen/ibcdata/"
 DOTNET_DIR = "/opt/usr/dotnet/"
 OWNER_DIR = "/home/owner/"
 SPC_DLL = "System.Private.CoreLib.dll"
+CROSSGEN2_OPTION = "--crossgen2"
 
 # Check the sdb connection status and get a device serial number
 def read_serial(serial):
@@ -113,7 +114,7 @@ def get_device_type():
 def create_spc_ni():
     raw = cmd(f"shell find {RUNTIME_DIR} -name {SPC_DLL}.Backup")
     if f"{RUNTIME_DIR}{SPC_DLL}.Backup" not in raw:
-        raw = cmd(f"shell dotnettool --ni-dll {RUNTIME_DIR}{SPC_DLL}")
+        raw = cmd(f"shell dotnettool {CROSSGEN2_OPTION} --ni-dll {RUNTIME_DIR}{SPC_DLL}")
         if "System.Private.CoreLib.ni.dll generated successfully." not in raw:
             return "FAIL"