From: 조웅석/Common Platform Lab(SR)/Principal Engineer/삼성전자 Date: Thu, 9 Sep 2021 06:34:53 +0000 (+0900) Subject: Modified to support crossgen2 (#330) X-Git-Tag: submit/tizen/20210909.063632~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=fb9e2ba7a941ea6fff1040e08e3507b15180b446;p=platform%2Fcore%2Fdotnet%2Flauncher.git Modified to support crossgen2 (#330) * 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. --- diff --git a/NativeLauncher/inc/ni_common.h b/NativeLauncher/inc/ni_common.h index d12b4b2..989e199 100644 --- a/NativeLauncher/inc/ni_common.h +++ b/NativeLauncher/inc/ni_common.h @@ -31,6 +31,10 @@ #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 afterCreate; diff --git a/NativeLauncher/installer-plugin/prefer_dotnet_aot_plugin.cc b/NativeLauncher/installer-plugin/prefer_dotnet_aot_plugin.cc index 6f93e44..57b2182 100644 --- a/NativeLauncher/installer-plugin/prefer_dotnet_aot_plugin.cc +++ b/NativeLauncher/installer-plugin/prefer_dotnet_aot_plugin.cc @@ -17,6 +17,7 @@ #include "ni_common.h" #include "log.h" #include "utils.h" +#include #include #include @@ -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; } diff --git a/NativeLauncher/tool/dotnettool.cc b/NativeLauncher/tool/dotnettool.cc index dc3cfcf..b6f51c8 100644 --- a/NativeLauncher/tool/dotnettool.cc +++ b/NativeLauncher/tool/dotnettool.cc @@ -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); } diff --git a/NativeLauncher/tool/ni_common.cc b/NativeLauncher/tool/ni_common.cc index e2e9f4d..23e9ec5 100644 --- a/NativeLauncher/tool/ni_common.cc +++ b/NativeLauncher/tool/ni_common.cc @@ -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 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& 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& args, const std::vector& 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 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& 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& dllList, const std::vector& 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 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(argv.data())); + + clearArgs(argv); + exit(0); + } + + return NI_ERROR_NONE; +} + +static ni_error_e crossgen2NoPipeLine(const std::vector& dllList, const std::vector& 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 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(argv.data())); + + clearArgs(argv); + exit(0); + } + + waitInterval(); + } + + return NI_ERROR_NONE; +} + + +static ni_error_e doAOTList(std::vector& 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 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 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 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 needNIList; + std::vector niList; + + for (auto &dll : dllList) { + if (!checkNIExistence(dll)) { + needNIList.push_back(dll); } - }; + niList.push_back(getNIFilePath(dll)); + } - std::vector 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 fileList; + std::vector 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; diff --git a/dotnet-launcher.manifest b/dotnet-launcher.manifest index 71d0ad6..05c7b6b 100644 --- a/dotnet-launcher.manifest +++ b/dotnet-launcher.manifest @@ -7,5 +7,6 @@ + diff --git a/packaging/dotnet-launcher.spec b/packaging/dotnet-launcher.spec index e4dd257..cc6d8f5 100644 --- a/packaging/dotnet-launcher.spec +++ b/packaging/dotnet-launcher.spec @@ -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 diff --git a/tests/TCs/6_TOOL/TOOL.py b/tests/TCs/6_TOOL/TOOL.py index 8635f0f..7629d7a 100755 --- a/tests/TCs/6_TOOL/TOOL.py +++ b/tests/TCs/6_TOOL/TOOL.py @@ -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" diff --git a/tests/TCs/Utils.py b/tests/TCs/Utils.py index 0a25754..03928b6 100755 --- a/tests/TCs/Utils.py +++ b/tests/TCs/Utils.py @@ -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"