Add Self-Contained Deployment Launcher 24/117224/4
authorchunseok lee <chunseok.lee@samsung.com>
Mon, 20 Feb 2017 06:50:30 +0000 (15:50 +0900)
committerchunseok lee <chunseok.lee@samsung.com>
Tue, 7 Mar 2017 08:11:38 +0000 (17:11 +0900)
Change-Id: I889de90eb72a645a32eb8110030fdb0496137d43
Signed-off-by: chunseok lee <chunseok.lee@samsung.com>
NativeLauncher/CMakeLists.txt
NativeLauncher/launcher/dotnet/scd_launcher.cc [new file with mode: 0644]
packaging/dotnet-launcher.spec

index 5398487..6799712 100755 (executable)
@@ -7,7 +7,7 @@ IF(DEFINED NO_TIZEN)
        SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -DNO_TIZEN")
 ELSE(DEFINED NO_TIZEN)
        INCLUDE(FindPkgConfig)
-       PKG_CHECK_MODULES(${PROJECT_NAME} REQUIRED aul pkgmgr-info pkgmgr-installer dlog ecore bundle dlog launchpad elementary glib-2.0)
+       PKG_CHECK_MODULES(${PROJECT_NAME} REQUIRED aul pkgmgr-info pkgmgr-installer dlog ecore bundle dlog launchpad elementary glib-2.0 capi-appfw-app-control capi-appfw-service-application)
 ENDIF(DEFINED NO_TIZEN)
 
 FOREACH(flag ${${PROJECT_NAME}_CFLAGS})
@@ -70,6 +70,21 @@ SET(${DOTNET_LAUNCHER}_SOURCE_FILES
 ADD_EXECUTABLE(${DOTNET_LAUNCHER} ${${DOTNET_LAUNCHER}_SOURCE_FILES})
 SET_TARGET_PROPERTIES(${DOTNET_LAUNCHER}       PROPERTIES COMPILE_FLAGS "-fPIE")
 
+
+SET(SCD_LAUNCHER "scd-launcher")
+SET(${SCD_LAUNCHER}_SOURCE_FILES
+       launcher/dotnet/scd_launcher.cc
+)
+ADD_EXECUTABLE(${SCD_LAUNCHER} ${${SCD_LAUNCHER}_SOURCE_FILES})
+SET_TARGET_PROPERTIES(${SCD_LAUNCHER}  PROPERTIES COMPILE_FLAGS "-fPIE")
+
+
+IF(NOT DEFINED NO_TIZEN)
+       TARGET_LINK_LIBRARIES(${SCD_LAUNCHER} capi-appfw-app-control dlog appcore-agent)
+ENDIF(NOT DEFINED NO_TIZEN)
+TARGET_LINK_LIBRARIES(${SCD_LAUNCHER} ${${PROJECT_NAME}_LDFLAGS} "-pie -ldl -lpthread")
+
+
 IF(NOT DEFINED NO_TIZEN)
        TARGET_LINK_LIBRARIES(${DOTNET_LAUNCHER} aul)
 ENDIF(NOT DEFINED NO_TIZEN)
@@ -113,6 +128,7 @@ TARGET_LINK_LIBRARIES(${PREFER_DOTNET_AOT_PLUGIN} ${${PROJECT_NAME}_LDFLAGS})
 
 IF(NOT DEFINED NO_TIZEN)
        INSTALL(TARGETS ${DOTNET_LAUNCHER} DESTINATION ${BINDIR})
+        INSTALL(TARGETS ${SCD_LAUNCHER} DESTINATION ${BINDIR})
        INSTALL(TARGETS ${NITOOL} DESTINATION ${BINDIR})
        INSTALL(TARGETS ${INSTALLER_PLUGIN} DESTINATION ${INSTALL_PLUGIN_DIR})
        INSTALL(TARGETS ${PREFER_DOTNET_AOT_PLUGIN} DESTINATION ${INSTALL_MDPLUGIN_DIR})
diff --git a/NativeLauncher/launcher/dotnet/scd_launcher.cc b/NativeLauncher/launcher/dotnet/scd_launcher.cc
new file mode 100644 (file)
index 0000000..9c573e8
--- /dev/null
@@ -0,0 +1,666 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include <cstdlib>
+#include <cstring>
+
+#include <string>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <set>
+
+// for serive_app
+#include <tizen.h>
+#include <service_app.h>
+#include <app_control.h>
+#include <dlog/dlog.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <vector>
+#include <unistd.h>
+#include <errno.h>
+#include <linux/limits.h>
+
+#include "dotnet_launcher.h"
+
+using namespace std;
+
+
+
+bool isDebugMode = false;
+char *coreclr_gdbjit[PATH_MAX];
+char *root_path;
+
+bool service_app_create(void *data)
+{
+  // Todo: add your code here.
+  return true;
+}
+
+void service_app_terminate(void *data)
+{
+  // Todo: add your code here.
+
+  return;
+}
+
+void service_app_control(app_control_h app_control, void *data)
+{
+  // Get _DEBUG_ value
+  char* buf[82];
+  int ret = app_control_get_extra_data(app_control, "_SCD_DEBUG_", buf);
+
+  if (ret == APP_CONTROL_ERROR_NONE) {
+    if(strcmp(*buf, "1") == 0) {
+      isDebugMode = true;
+    }
+  }
+  if (isDebugMode) {
+    ret = app_control_get_extra_data(app_control, "_SCD_CORECLR_GDBJIT_", coreclr_gdbjit);
+  }
+
+  service_app_exit();
+  return;
+}
+
+
+//
+// A simple CoreCLR host that runs a managed binary with the same name as this executable but with the *.dll extension
+// The dll binary must contain a main entry point.
+//
+
+#ifndef SUCCEEDED
+#define SUCCEEDED(Status) ((Status) >= 0)
+#endif // !SUCCEEDED
+
+static const char * const coreClrDll = "libcoreclr.so";
+// Name of the environment variable controlling server GC.
+// If set to 1, server GC is enabled on startup. If 0, server GC is
+// disabled. Server GC is off by default.
+static const char* serverGcVar = "CORECLR_SERVER_GC";
+#define symlinkEntrypointExecutable "/proc/self/exe"
+
+bool GetEntrypointExecutableAbsolutePath(std::string& entrypointExecutable)
+{
+  bool result = false;
+
+  entrypointExecutable.clear();
+
+  // Get path to the executable for the current process using
+  // platform specific means.
+
+  // On Linux, fetch the entry point EXE absolute path, inclusive of filename.
+  char exe[PATH_MAX];
+  ssize_t res = readlink(symlinkEntrypointExecutable, exe, PATH_MAX - 1);
+  if (res != -1)
+    {
+      exe[res] = '\0';
+      entrypointExecutable.assign(exe);
+      result = true;
+    }
+  else
+    {
+      result = false;
+    }
+
+  return result;
+}
+
+bool GetAbsolutePath(const char* path, std::string& absolutePath)
+{
+  bool result = false;
+
+  char realPath[PATH_MAX];
+  if (realpath(path, realPath) != nullptr && realPath[0] != '\0')
+    {
+      absolutePath.assign(realPath);
+      // realpath should return canonicalized path without the trailing slash
+      assert(absolutePath.back() != '/');
+
+      result = true;
+    }
+
+  return result;
+}
+
+
+
+bool GetDirectory(const char* absolutePath, std::string& directory)
+{
+  directory.assign(absolutePath);
+  size_t lastSlash = directory.rfind('/');
+  if (lastSlash != std::string::npos)
+    {
+      directory.erase(lastSlash);
+      return true;
+    }
+
+  return false;
+}
+
+bool GetClrFilesAbsolutePath(const char* currentExePath, const char* clrFilesPath, std::string& clrFilesAbsolutePath)
+{
+  std::string clrFilesRelativePath;
+  const char* clrFilesPathLocal = clrFilesPath;
+  if (clrFilesPathLocal == nullptr)
+    {
+      // There was no CLR files path specified, use the folder of the corerun/coreconsole
+      if (!GetDirectory(currentExePath, clrFilesRelativePath))
+        {
+          perror("Failed to get directory from argv[0]");
+          return false;
+        }
+
+      clrFilesPathLocal = clrFilesRelativePath.c_str();
+
+      // TODO: consider using an env variable (if defined) as a fall-back.
+      // The windows version of the corerun uses core_root env variable
+    }
+
+  if (!GetAbsolutePath(clrFilesPathLocal, clrFilesAbsolutePath))
+    {
+      perror("Failed to convert CLR files path to absolute path");
+      return false;
+    }
+
+  return true;
+}
+
+void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList)
+{
+  const char * const tpaExtensions[] = {
+    ".ni.dll",      // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir
+    ".dll",
+    ".ni.exe",
+    ".exe",
+  };
+
+  DIR* dir = opendir(directory);
+  if (dir == nullptr)
+    {
+      return;
+    }
+
+  std::set<std::string> addedAssemblies;
+
+  // Walk the directory for each extension separately so that we first get files with .ni.dll extension,
+  // then files with .dll extension, etc.
+  for (int extIndex = 0; extIndex < sizeof(tpaExtensions) / sizeof(tpaExtensions[0]); extIndex++)
+    {
+      const char* ext = tpaExtensions[extIndex];
+      int extLength = strlen(ext);
+
+      struct dirent* entry;
+
+      // For all entries in the directory
+      while ((entry = readdir(dir)) != nullptr)
+        {
+          // We are interested in files only
+          switch (entry->d_type)
+            {
+            case DT_REG:
+              break;
+
+              // Handle symlinks and file systems that do not support d_type
+            case DT_LNK:
+            case DT_UNKNOWN:
+              {
+                std::string fullFilename;
+
+                fullFilename.append(directory);
+                fullFilename.append("/");
+                fullFilename.append(entry->d_name);
+
+                struct stat sb;
+                if (stat(fullFilename.c_str(), &sb) == -1)
+                  {
+                    continue;
+                  }
+
+                if (!S_ISREG(sb.st_mode))
+                  {
+                    continue;
+                  }
+              }
+              break;
+
+            default:
+              continue;
+            }
+
+          std::string filename(entry->d_name);
+
+          // Check if the extension matches the one we are looking for
+          int extPos = filename.length() - extLength;
+          if ((extPos <= 0) || (filename.compare(extPos, extLength, ext) != 0))
+            {
+              continue;
+            }
+
+          std::string filenameWithoutExt(filename.substr(0, extPos));
+
+          // Make sure if we have an assembly with multiple extensions present,
+          // we insert only one version of it.
+          if (addedAssemblies.find(filenameWithoutExt) == addedAssemblies.end())
+            {
+              addedAssemblies.insert(filenameWithoutExt);
+
+              tpaList.append(directory);
+              tpaList.append("/");
+              tpaList.append(filename);
+              tpaList.append(":");
+            }
+        }
+
+      // Rewind the directory stream to be able to iterate over it for the next extension
+      rewinddir(dir);
+    }
+
+  closedir(dir);
+}
+
+
+
+int ExecuteManagedAssembly(
+                           const char* currentExeAbsolutePath,
+                           const char* clrFilesAbsolutePath,
+                           const char* managedAssemblyAbsolutePath,
+                           int managedAssemblyArgc,
+                           const char** managedAssemblyArgv)
+{
+  // Indicates failure
+  int exitCode = -1;
+
+#ifdef _ARM_
+  // libunwind library is used to unwind stack frame, but libunwind for ARM
+  // does not support ARM vfpv3/NEON registers in DWARF format correctly.
+  // Therefore let's disable stack unwinding using DWARF information
+  // See https://github.com/dotnet/coreclr/issues/6698
+  //
+  // libunwind use following methods to unwind stack frame.
+  // UNW_ARM_METHOD_ALL          0xFF
+  // UNW_ARM_METHOD_DWARF        0x01
+  // UNW_ARM_METHOD_FRAME        0x02
+  // UNW_ARM_METHOD_EXIDX        0x04
+  putenv(const_cast<char *>("UNW_ARM_UNWIND_METHOD=6"));
+#endif // _ARM_
+
+  std::string coreClrDllPath(clrFilesAbsolutePath);
+  coreClrDllPath.append("/");
+  coreClrDllPath.append(coreClrDll);
+
+  if (coreClrDllPath.length() >= PATH_MAX)
+    {
+      fprintf(stderr, "Absolute path to libcoreclr.so too long\n");
+      return -1;
+    }
+
+  // Get just the path component of the managed assembly path
+  std::string appPath;
+  GetDirectory(managedAssemblyAbsolutePath, appPath);
+
+  std::string tpaList;
+  // Construct native search directory paths
+  std::string nativeDllSearchDirs(appPath);
+  char *coreLibraries = getenv("CORE_LIBRARIES");
+  if (coreLibraries)
+    {
+      nativeDllSearchDirs.append(":");
+      nativeDllSearchDirs.append(coreLibraries);
+      if (std::strcmp(coreLibraries, clrFilesAbsolutePath) != 0)
+        {
+          AddFilesFromDirectoryToTpaList(coreLibraries, tpaList);
+        }
+    }
+  nativeDllSearchDirs.append(":");
+  nativeDllSearchDirs.append(clrFilesAbsolutePath);
+
+  AddFilesFromDirectoryToTpaList(clrFilesAbsolutePath, tpaList);
+
+  void* coreclrLib = dlopen(coreClrDllPath.c_str(), RTLD_NOW | RTLD_LOCAL);
+  if (coreclrLib != nullptr)
+    {
+      coreclr_initialize_ptr initializeCoreCLR = (coreclr_initialize_ptr)dlsym(coreclrLib, "coreclr_initialize");
+      coreclr_execute_assembly_ptr executeAssembly = (coreclr_execute_assembly_ptr)dlsym(coreclrLib, "coreclr_execute_assembly");
+      coreclr_shutdown_ptr shutdownCoreCLR = (coreclr_shutdown_ptr)dlsym(coreclrLib, "coreclr_shutdown");
+
+      if (initializeCoreCLR == nullptr)
+        {
+          fprintf(stderr, "Function coreclr_initialize not found in the libcoreclr.so\n");
+        }
+      else if (executeAssembly == nullptr)
+        {
+          fprintf(stderr, "Function coreclr_execute_assembly not found in the libcoreclr.so\n");
+        }
+      else if (shutdownCoreCLR == nullptr)
+        {
+          fprintf(stderr, "Function coreclr_shutdown not found in the libcoreclr.so\n");
+        }
+      else
+        {
+          // Check whether we are enabling server GC (off by default)
+          const char* useServerGc = std::getenv(serverGcVar);
+          if (useServerGc == nullptr)
+            {
+              useServerGc = "0";
+            }
+
+          // CoreCLR expects strings "true" and "false" instead of "1" and "0".
+          useServerGc = std::strcmp(useServerGc, "1") == 0 ? "true" : "false";
+
+          // Allowed property names:
+          // APPBASE
+          // - The base path of the application from which the exe and other assemblies will be loaded
+          //
+          // TRUSTED_PLATFORM_ASSEMBLIES
+          // - The list of complete paths to each of the fully trusted assemblies
+          //
+          // APP_PATHS
+          // - The list of paths which will be probed by the assembly loader
+          //
+          // APP_NI_PATHS
+          // - The list of additional paths that the assembly loader will probe for ngen images
+          //
+          // NATIVE_DLL_SEARCH_DIRECTORIES
+          // - The list of paths that will be probed for native DLLs called by PInvoke
+          //
+          const char *propertyKeys[] = {
+            "TRUSTED_PLATFORM_ASSEMBLIES",
+            "APP_PATHS",
+            "APP_NI_PATHS",
+            "NATIVE_DLL_SEARCH_DIRECTORIES",
+            "System.GC.Server",
+          };
+          const char *propertyValues[] = {
+            // TRUSTED_PLATFORM_ASSEMBLIES
+            tpaList.c_str(),
+            // APP_PATHS
+            appPath.c_str(),
+            // APP_NI_PATHS
+            appPath.c_str(),
+            // NATIVE_DLL_SEARCH_DIRECTORIES
+            nativeDllSearchDirs.c_str(),
+            // System.GC.Server
+            useServerGc,
+          };
+
+          void* hostHandle;
+          unsigned int domainId;
+
+          int st = initializeCoreCLR(
+                                     currentExeAbsolutePath,
+                                     "unixcorerun",
+                                     sizeof(propertyKeys) / sizeof(propertyKeys[0]),
+                                     propertyKeys,
+                                     propertyValues,
+                                     &hostHandle,
+                                     &domainId);
+
+          if (!SUCCEEDED(st))
+            {
+              fprintf(stderr, "coreclr_initialize failed - status: 0x%08x\n", st);
+              exitCode = -1;
+            }
+          else
+            {
+              st = executeAssembly(
+                                   hostHandle,
+                                   domainId,
+                                   managedAssemblyArgc,
+                                   managedAssemblyArgv,
+                                   managedAssemblyAbsolutePath,
+                                   (unsigned int*)&exitCode);
+
+              if (!SUCCEEDED(st))
+                {
+                  fprintf(stderr, "coreclr_execute_assembly failed - status: 0x%08x\n", st);
+                  exitCode = -1;
+                }
+
+              st = shutdownCoreCLR(hostHandle, domainId);
+              if (!SUCCEEDED(st))
+                {
+                  fprintf(stderr, "coreclr_shutdown failed - status: 0x%08x\n", st);
+                  exitCode = -1;
+                }
+            }
+        }
+
+      if (dlclose(coreclrLib) != 0)
+        {
+          fprintf(stderr, "Warning - dlclose failed\n");
+        }
+    }
+  else
+    {
+      const char* error = dlerror();
+      fprintf(stderr, "dlopen failed to open the libcoreclr.so with error %s\n", error);
+    }
+
+  return exitCode;
+}
+
+
+// Display the help text
+void DisplayUsage()
+{
+  fprintf(
+          stderr,
+          "Runs executables on CoreCLR\n\n"
+          "Usage: <program> [OPTIONS] [ARGUMENTS]\n"
+          "Runs <program>.dll on CoreCLR.\n\n"
+          "Options:\n"
+          "-_c  path to libcoreclr.so and the managed CLR assemblies.\n"
+          "-_h  show this help message. \n");
+}
+
+// Parse the command line arguments
+bool ParseArguments(
+                    const int argc,
+                    const char* argv[],
+                    const char** clrFilesPath,
+                    int* managedAssemblyArgc,
+                    const char*** managedAssemblyArgv)
+{
+  bool success = true;
+
+  *clrFilesPath = nullptr;
+  *managedAssemblyArgv = nullptr;
+  *managedAssemblyArgc = 0;
+
+  for (int i = 1; i < argc; i++)
+    {
+      // Check for options. Options to the Unix coreconsole are prefixed with '-_' to match the convention
+      // used in the Windows version of coreconsole.
+      if (strncmp(argv[i], "-_", 2) == 0)
+        {
+          // Path to the libcoreclr.so and the managed CLR assemblies
+          if (strcmp(argv[i], "-_c") == 0)
+            {
+              i++;
+              if (i < argc)
+                {
+                  *clrFilesPath = argv[i];
+                }
+              else
+                {
+                  fprintf(stderr, "Option %s: missing path\n", argv[i - 1]);
+                  success = false;
+                  break;
+                }
+            }
+          else if (strcmp(argv[i], "-_h") == 0)
+            {
+              DisplayUsage();
+              success = false;
+              break;
+            }
+          else
+            {
+              fprintf(stderr, "Unknown option %s\n", argv[i]);
+              success = false;
+              break;
+            }
+        }
+      else
+        {
+          // We treat everything starting from the first non-option argument as arguments
+          // to the managed assembly.
+          *managedAssemblyArgc = argc - i;
+          if (*managedAssemblyArgc != 0)
+            {
+              *managedAssemblyArgv = &argv[i];
+            }
+
+          break;
+        }
+    }
+
+  return success;
+}
+
+int main(const int argc, const char* argv[])
+{
+  /// service_app_begin
+  char *root_path = getenv("AUL_ROOT_PATH");
+  char *second_pass = getenv("SECONDPASS");
+
+  // This routine check whether _SCD_DEBUG_ flag is set(1) or not.
+  // In second pass, this routine is skipped.
+  if (second_pass == NULL) {
+    // run service_app routine to extract _SCD_DEBUG_
+    char ad[50] = {0,};
+    service_app_lifecycle_callback_s event_callback;
+    event_callback.create = service_app_create;
+    event_callback.terminate = service_app_terminate;
+    event_callback.app_control = service_app_control;
+    // FIXME: casting of argv is safe ?
+    service_app_main(argc, (char**)argv, &event_callback, ad);
+
+    char buf[PATH_MAX];
+    vector<const char*> vargs;
+    int status = 0;
+
+    if (isDebugMode) {
+      dlog_print(DLOG_INFO,"dotnet","debugmode on\n");
+      setenv("CORECLR_GDBJIT", *coreclr_gdbjit, 1);
+
+      string cur_path(getenv("PATH"));
+      string new_path("/home/owner/share/tmp/sdk_tools/lldb/bin:");
+      new_path.append(cur_path);
+      setenv("PATH", new_path.c_str(), 1);
+
+      vargs.push_back("/home/owner/share/tmp/sdk_tools/lldb/bin/lldb-server");
+      vargs.push_back("g");
+      vargs.push_back("--platform=host");
+      vargs.push_back("*:1234");
+      vargs.push_back("--");
+    }
+    snprintf(buf, sizeof(buf), "%s/bin/%s", root_path, basename(root_path));
+    vargs.push_back(buf);
+
+    // Pass app argument to lldb-server as it is
+    for (int i=1; i<argc; i++) {
+      vargs.push_back(argv[i]);
+    }
+
+    const char** new_args = &vargs[0];
+    setenv("SECONDPASS", "1", 1);
+    status = execvp(new_args[0], (char *const *)new_args);
+    dlog_print(DLOG_INFO,"dotnet","something wrong errno: %d\n",errno);
+  }
+  /// service_app_end
+
+
+
+  // Make sure we have a full path for argv[0].
+  std::string argv0AbsolutePath;
+  std::string entryPointExecutablePath;
+
+  if (!GetEntrypointExecutableAbsolutePath(entryPointExecutablePath))
+    {
+      perror("Could not get full path to current executable");
+      return -1;
+    }
+
+  if (!GetAbsolutePath(entryPointExecutablePath.c_str(), argv0AbsolutePath))
+    {
+      perror("Could not normalize full path to current executable");
+      return -1;
+    }
+
+  // We will try to load the managed assembly with the same name as this executable
+  // but with the .dll extension.
+  std::string programPath(argv0AbsolutePath);
+  programPath.append(".dll");
+  const char* managedAssemblyAbsolutePath = programPath.c_str();
+
+  // Check if the specified managed assembly file exists
+  struct stat sb;
+  if (stat(managedAssemblyAbsolutePath, &sb) == -1)
+    {
+      perror("Managed assembly not found");
+      return -1;
+    }
+
+  // Verify that the managed assembly path points to a file
+  if (!S_ISREG(sb.st_mode))
+    {
+      fprintf(stderr, "The specified managed assembly is not a file\n");
+      return -1;
+    }
+
+  const char* clrFilesPath;
+  const char** managedAssemblyArgv;
+  int managedAssemblyArgc;
+
+  if (!ParseArguments(
+                      argc,
+                      argv,
+                      &clrFilesPath,
+                      &managedAssemblyArgc,
+                      &managedAssemblyArgv
+                      ))
+    {
+      // Invalid command line
+      return -1;
+    }
+
+  std::string clrFilesAbsolutePath;
+  if(!GetClrFilesAbsolutePath(argv0AbsolutePath.c_str(), clrFilesPath, clrFilesAbsolutePath))
+    {
+      return -1;
+    }
+
+  int exitCode = ExecuteManagedAssembly(
+                                        argv0AbsolutePath.c_str(),
+                                        clrFilesAbsolutePath.c_str(),
+                                        managedAssemblyAbsolutePath,
+                                        managedAssemblyArgc,
+                                        managedAssemblyArgv);
+
+  return exitCode;
+}
index cc4fd79..4ce5d38 100755 (executable)
@@ -20,6 +20,15 @@ BuildRequires: pkgconfig(glib-2.0)
 BuildRequires: aul-devel
 BuildRequires: dotnet-build-tools
 
+# Required by scd-launcher
+BuildRequires: appcore-agent
+BuildRequires: pkgconfig(appcore-agent)
+BuildRequires: pkgconfig(capi-appfw-app-control)
+BuildRequires: pkgconfig(capi-appfw-application)
+BuildRequires: pkgconfig(capi-appfw-service-application)
+BuildRequires: pkgconfig(capi-appfw-service-application)
+
+
 Requires: aul
 
 Requires(post): /sbin/ldconfig
@@ -40,6 +49,12 @@ ExcludeArch: aarch64
 %description
 Launchpad plugin for launching dotnet apps
 
+%package -n scd-launcher
+Summary:    self-contained dotnet launcher
+%description -n scd-launcher
+launching dotnet apps without dotent runtime installed
+
+
 %prep
 %setup -q
 
@@ -93,3 +108,6 @@ install -p -m 644 Tizen.Runtime/bin/Tizen.Runtime.Mono.dll %{buildroot}%{_bindir
 %caps(cap_mac_admin,cap_setgid=ei) %{_install_mdplugin_dir}/libprefer_dotnet_aot_plugin.so
 %caps(cap_mac_admin,cap_setgid=ei) %{_bindir}/Tizen.Runtime.Coreclr.dll
 %caps(cap_mac_admin,cap_setgid=ei) %{_bindir}/Tizen.Runtime.Mono.dll
+
+%files -n scd-launcher
+%caps(cap_mac_admin,cap_setgid=ei) %{_bindir}/scd-launcher