Split Native Parts to SharedObject and Executable
authorpius.lee <pius.lee@samsung.com>
Fri, 26 Aug 2016 07:40:52 +0000 (16:40 +0900)
committerpius.lee <pius.lee@samsung.com>
Fri, 26 Aug 2016 07:40:52 +0000 (16:40 +0900)
Make libdnclauncher.so for waiting and launchpad callbacks.
Modify dotnet-launcher to execute managed launcher with libcoreclr.so.
Managed Launcher read ini file to read dll lists for preloading.
Add Targets file building csproj with corefx and device apis.

15 files changed:
NativeLauncher/CMakeLists.txt
NativeLauncher/dotnet-launcher.ini
NativeLauncher/src/launcher.cc
NativeLauncher/src/launcher.h
NativeLauncher/src/waiter.cc
NativeLauncher/src/waiter.h
Tizen.Runtime/Tizen.CoreFX.Ref.Targets
Tizen.Runtime/Tizen.Runtime.csproj
Tizen.Runtime/Tizen.Runtime/AssemblyLoader.cs
Tizen.Runtime/Tizen.Runtime/AssemblyManager.cs
Tizen.Runtime/Tizen.Runtime/DefaultConfigAttribute.cs [new file with mode: 0644]
Tizen.Runtime/Tizen.Runtime/Ini.cs [new file with mode: 0644]
Tizen.Runtime/Tizen.Runtime/Interop.cs [new file with mode: 0644]
packaging/dotnet-launcher.spec
test_build_on_desktop.sh [new file with mode: 0755]

index e55c12c..8e203a3 100644 (file)
@@ -14,14 +14,18 @@ FOREACH(flag ${${PROJECT_NAME}_CFLAGS})
        SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
 ENDFOREACH(flag)
 
-IF(DEFINED LAUNCHER_PATH)
-       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -DLAUNCHER_PATH=${LAUNCHER_PATH}")
-ENDIF(DEFINED LAUNCHER_PATH)
+IF(DEFINED LAUNCHER_CONFIG_PATH)
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -DLAUNCHER_CONFIG_PATH=${LAUNCHER_CONFIG_PATH}")
+ENDIF(DEFINED LAUNCHER_CONFIG_PATH)
+
+IF(DEFINED LAUNCHER_ASSEMBLY_PATH)
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -DLAUNCHER_ASSEMBLY_PATH=${LAUNCHER_ASSEMBLY_PATH}")
+ENDIF(DEFINED LAUNCHER_ASSEMBLY_PATH)
 
 
 SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -std=c++11")
 SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wl,-zdefs" )
-SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden")
+#SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden")
 SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fPIE")
 SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fdata-sections -ffunction-sections -Wl,--gc-sections")
 SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -D_FILE_OFFSET_BITS=64")
@@ -48,8 +52,16 @@ SET_TARGET_PROPERTIES(${PROJECT_NAME}
        PROPERTIES SKIP_BUILD_RPATH TRUE
        ) # remove rpath option that is automatically generated by cmake.
 
+SET(LAUNCHER_LIB "dnclauncher")
+ADD_LIBRARY(${LAUNCHER_LIB} SHARED src/waiter.cc)
+IF(NOT DEFINED NO_TIZEN)
+       TARGET_LINK_LIBRARIES(${LAUNCHER_LIB} aul)
+ENDIF(NOT DEFINED NO_TIZEN)
+TARGET_LINK_LIBRARIES(${LAUNCHER_LIB} ${${PROJECT_NAME}_LDFLAGS} "-ldl")
+
 IF(NOT DEFINED NO_TIZEN)
        INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${BINDIR})
+       INSTALL(TARGETS ${LAUNCHER_LIB} DESTINATION ${LIBDIR})
        INSTALL(FILES dotnet.loader DESTINATION ${LOADERDIR})
        INSTALL(FILES dotnet-launcher.ini DESTINATION ${CONFIGDIR})
 ENDIF(NOT DEFINED NO_TIZEN)
index 9d4809c..ad1d22b 100644 (file)
@@ -1,5 +1,6 @@
 [dotnet]
-libcoreclr = libcoreclr.so
+libcoreclr = /opt/usr/share/dotnet/shared/Microsoft.NETCore.App/1.0.0/libcoreclr.so
 coreclr_dir = /opt/usr/share/dotnet/shared/Microsoft.NETCore.App/1.0.0
 tpa_dirs = /opt/usr/share/dotnet/shared/Microsoft.NETCore.App/1.0.0:/usr/share/assembly
 native_so_search_dirs = /opt/usr/share/dotnet/shared/Microsoft.NETCore.App/1.0.0:/usr/share/assembly
+launcher_assembly = /usr/bin/Tizen.Runtime.dll
index fcd1555..84c3811 100644 (file)
@@ -1,9 +1,5 @@
 #include <dlfcn.h>
 
-#ifdef LAUNCHING_TIME_MEASURE
-#include <ctime>
-#endif
-
 #include <cstdlib>
 #include <cstring>
 #include <vector>
 #include <dirent.h>
 #include <sys/stat.h>
 
+#include <unistd.h>
+#include <limits.h>
+
 #include "environment.h"
 #include "waiter.h"
 #include "log.h"
 
 #include "tini.hpp"
 
-#include "launcher.h"
-
-namespace dotnet {
-namespace runtime {
-
-#ifdef LAUNCHER_PATH
 #define __STR(x) #x
 #define __XSTR(x) __STR(x)
-#define LAUNCHER_CONFIG __XSTR(LAUNCHER_PATH)
+
+#ifdef LAUNCHER_CONFIG_PATH
+#define LAUNCHER_CONFIG __XSTR(LAUNCHER_CONFIG_PATH)
 #else
 #define LAUNCHER_CONFIG "/etc/dotnet-launcher.ini"
 #endif
 static const std::string LauncherConfig(LAUNCHER_CONFIG);
-#ifdef LAUNCHER_PATH
-#undef __STR
-#undef __XSTR
+#ifdef LAUNCHER_CONFIG_PATH
 #undef LAUNCHER_CONFIG
-#undef LAUNCHER_PATH
+#undef LAUNCHER_CONFIG_PATH
 #endif
+#undef __STR
+#undef __XSTR
 
 #ifndef PATH_SEPARATOR
 #define PATH_SEPARATOR '/'
 #endif
 
+typedef int (*coreclr_initialize_ptr)(
+    const char* exePath,
+    const char* appDomainFriendlyName,
+    int propertyCount,
+    const char** propertyKeys,
+    const char** propertyValues,
+    void** hostHandle,
+    unsigned int* domainId);
+
+typedef int (*coreclr_execute_assembly_ptr)(
+    void* hostHandle,
+    unsigned int domainId,
+    int argc,
+    const char** argv,
+    const char* managedAssemblyPath,
+    unsigned int* exitCode);
+
+typedef int (*coreclr_shutdown_ptr)(
+    void* hostHandle,
+    unsigned int domainId);
+
+typedef int (*coreclr_create_delegate_ptr)(
+    void* hostHandle,
+    unsigned int domainId,
+    const char* entryPointAssemblyName,
+    const char* entryPointTypeName,
+    const char* entryPointMethodName,
+    void** delegate);
+
+std::string ReadSelfPath() {
+  char buff[PATH_MAX];
+  ssize_t len = ::readlink("/proc/self/exe", buff, sizeof(buff)-1);
+  if (len != -1) {
+    buff[len] = '\0';
+    return std::string(buff);
+  }
+
+  return "";
+}
+
+/*
 static std::string ConcatPath(const std::string& path1, const std::string& path2)
 {
   std::string path(path1);
@@ -74,6 +110,7 @@ static void AppendPath(std::string& path1, const std::string& path2)
     path1.append(path2);
   }
 }
+*/
 
 static std::string AbsolutePath(const std::string& path)
 {
@@ -134,6 +171,8 @@ static std::string AssembliesInDirectory(const char *directory)
     return std::string();
   }
 
+  _DBG("assemblies in %s", directory);
+
   std::set<std::string> addedAssemblies;
 
   struct dirent *entry;
@@ -198,20 +237,8 @@ static std::string AssembliesInDirectory(const char *directory)
   return tpaList;
 }
 
-Launcher::Launcher()
+static int RunLauncherDll(int argc, char* argv[])
 {
-}
-
-Launcher::~Launcher()
-{
-}
-
-void Launcher::Initialize()
-{
-#ifdef LAUNCHING_TIME_MEASURE
-  std::clock_t start = std::clock();
-#endif
-
   std::ifstream iniStream(LauncherConfig);
   std::stringstream iniString;
   iniString << iniStream.rdbuf();
@@ -221,82 +248,56 @@ void Launcher::Initialize()
   _DBG("%s", launcherIni.to_string().c_str());
 
   auto &dotnet = launcherIni["dotnet"];
-  if (dotnet.find("libcoreclr") == dotnet.end())
-    dotnet["libcoreclr"] = "libcoreclr.so";
-  if (dotnet.find("coreclr_dir") == dotnet.end())
-    dotnet["coreclr_dir"] = "/usr/share/dotnet";
-  if (dotnet.find("tpa_dir") == dotnet.end())
-    dotnet["tpa_dir"] = dotnet["coreclr_dir"] + ":" + "/usr/share/assemblies";
-  if (dotnet.find("native_so_search_dirs") == dotnet.end())
-    dotnet["native_so_search_dirs"] = dotnet["tpa_dir"];
-
-  _DBG("libcoreclr : %s", dotnet["libcoreclr"].c_str());
-  _DBG("coreclr_dir : %s", dotnet["coreclr_dir"].c_str());
-  _DBG("tpa_dir : %s", dotnet["tpa_dir"].c_str());
-  _DBG("native_so_search_dirs : %s", dotnet["native_so_search_dirs"].c_str());
-
-  std::string libcoreclr = dotnet["coreclr_dir"] + "/" + dotnet["libcoreclr"];
-  std::string tpaDirs = dotnet["tpa_dirs"];
-  std::string nativeSoSearchDirs = dotnet["native_so_search_dirs"];
-
-  _DBG("libcoreclr.so : [%s]", libcoreclr.c_str());
-
-#ifdef LAUNCHING_TIME_MEASURE
-  std::clock_t config_read_time = std::clock();
-  _DBG("Reading Config file... : %Lf ms ", (config_read_time - start) / (double)(CLOCKS_PER_SEC / 1000));
-#endif
 
-  coreclrLib = dlopen(libcoreclr.c_str(), RTLD_NOW | RTLD_LOCAL);
-  if (coreclrLib == nullptr)
+#define DOTNET_FIND(key, defaultValue) \
+  ((dotnet.find(key) == dotnet.end()) ? defaultValue : dotnet[key])
+  std::string libcoreclr = DOTNET_FIND("libcoreclr", "libcoreclr.so");
+  std::string coreclr_dir = DOTNET_FIND("coreclr_dir", "/opt/usr/share/dotnet/shared/Microsoft.NETCore.App/1.0.0/");
+  std::string tpa_dirs = DOTNET_FIND("tpa_dirs", coreclr_dir + ":" + "/usr/share/assembly");
+  std::string native_so_search_dirs = DOTNET_FIND("native_so_search_dirs", tpa_dirs);
+  std::string launcher_assembly = AbsolutePath(DOTNET_FIND("launcher_assembly", "/usr/bin/Tizen.Runtime.dll"));
+#undef DOTNET_FIND
+
+  std::string launcher_dir = Basename(launcher_assembly);
+  std::string trusted_assemblies = launcher_assembly + ":";
+
+  std::istringstream f(tpa_dirs);
+  std::string s;
+  while (std::getline(f, s, ':'))
   {
-    char *err = dlerror();
-    _ERR("dlopen failed to open libcoreclr.so with error %s", err);
-    return;
+    trusted_assemblies += AssembliesInDirectory(s.c_str());
   }
 
-  initializeCoreCLR = (coreclr_initialize_ptr)dlsym(coreclrLib, "coreclr_initialize");
-  executeAssembly = (coreclr_execute_assembly_ptr)dlsym(coreclrLib, "coreclr_execute_assembly");
-  shutdownCoreCLR = (coreclr_shutdown_ptr)dlsym(coreclrLib, "coreclr_shutdown");
+  _DBG("libcoreclr : %s", libcoreclr.c_str());
+  _DBG("coreclr_dir : %s", coreclr_dir.c_str());
+  _DBG("tpa_dirs : %s", tpa_dirs.c_str());
+  _DBG("native_so_search_dir : %s", native_so_search_dirs.c_str());
+  _DBG("launcher_assembly : %s", launcher_assembly.c_str());
+  _DBG("launcher_dir : %s", launcher_dir.c_str());
+  _DBG("-------------------------------------------------");
 
-  if (initializeCoreCLR == nullptr)
-  {
-    _ERR("coreclr_initialize not found in the libcoreclr.so");
-  }
-  else if (executeAssembly == nullptr)
-  {
-    _ERR("coreclr_execute_assembly_ptr not found in the libcoreclr.so");
-  }
-  else if (shutdownCoreCLR == nullptr)
-  {
-    _ERR("coreclr_shutdown_ptr not found in the libcoreclr.so");
-  }
-  else
+  void *coreclrLib = dlopen(libcoreclr.c_str(), RTLD_NOW | RTLD_LOCAL);
+  if (coreclrLib == nullptr)
   {
-    std::istringstream f(tpaDirs);
-    std::string s;
-    while (std::getline(f, s, ':'))
-    {
-      TrustedPlatformAssemblies += AssembliesInDirectory(s.c_str());
-    }
-    NativeDllSearchDirectories = nativeSoSearchDirs; 
-    AppDomainCompatSwitch = "UseLatestBehaviorWhenTFMNotSpecified";
+    char *err = dlerror();
+    _ERR("dlopen failed to open libcoreclr.so with error %s", err);
+    return 1;
   }
 
-#ifdef LAUNCHING_TIME_MEASURE
-  std::clock_t dlopen_time = std::clock();
-  _DBG("dlopen and dlsym time... : %Lf ms ", (dlopen_time - config_read_time) / (double)(CLOCKS_PER_SEC / 1000));
-  _DBG("initialize time... : %Lf ms ", (dlopen_time - start) / (double)(CLOCKS_PER_SEC / 1000));
-#endif
+#define CORELIB_RETURN_IF_NOSYM(type, variable, name) \
+  type variable; \
+  do { variable = (type)dlsym(coreclrLib, name); \
+    if (variable == nullptr) { \
+      _ERR(name " is not found in the libcoreclr.so"); \
+      return 1; \
+    }} while(0)
 
-}
+  CORELIB_RETURN_IF_NOSYM(coreclr_initialize_ptr, coreclr_initialize, "coreclr_initialize");
+  CORELIB_RETURN_IF_NOSYM(coreclr_execute_assembly_ptr, coreclr_execute_assembly, "coreclr_execute_assembly");
+  CORELIB_RETURN_IF_NOSYM(coreclr_shutdown_ptr, coreclr_shutdown, "coreclr_shutdown");
+  CORELIB_RETURN_IF_NOSYM(coreclr_create_delegate_ptr, coreclr_create_delegate, "coreclr_create_delegate");
 
-void Launcher::Launch(const string& exe_path, const string& app_root, int argc, char *argv[])
-{
-  std::string bin_path = Basename(AbsolutePath(exe_path));
-  std::string lib_path = ConcatPath(AbsolutePath(app_root), "lib");
-  std::string app_path = bin_path + ":" + lib_path;
-  std::string app_ni_path = app_path;
-  std::string nativeDllSearchDirectories = NativeDllSearchDirectories + app_path;
+#undef CORELIB_RETURN_IF_NOSYM
 
   const char *propertyKeys[] =
   {
@@ -309,28 +310,27 @@ void Launcher::Launch(const string& exe_path, const string& app_root, int argc,
 
   const char *propertyValues[] =
   {
-    TrustedPlatformAssemblies.c_str(),
-    app_path.c_str(),
-    app_ni_path.c_str(),
-    nativeDllSearchDirectories.c_str(),
-    AppDomainCompatSwitch.c_str()
+    trusted_assemblies.c_str(),
+    launcher_dir.c_str(),
+    launcher_dir.c_str(),
+    native_so_search_dirs.c_str(),
+    "UseLatestBehaviorWhenTFMNotSpecified"
   };
 
-  //_DBG("trusted platform assemblies : %s", propertyValues[0]);
+  _DBG("trusted platform assemblies : %s", propertyValues[0]);
   _DBG("app_path : %s", propertyValues[1]);
   _DBG("app_ni_path : %s", propertyValues[2]);
   _DBG("native dll search path : %s", propertyValues[3]);
   _DBG("app domain compat switch : %s", propertyValues[4]);
 
+  _DBG("before initialize coreclr");
+
   void* hostHandle;
   unsigned int domainId;
 
-  _DBG("before initialize coreclr");
+  std::string selfPath = ReadSelfPath();
 
-#ifdef LAUNCHING_TIME_MEASURE
-  std::clock_t start = std::clock();
-#endif
-  int st = initializeCoreCLR(exe_path.c_str(),
+  int st = coreclr_initialize(selfPath.c_str(),
       "tizen_dotnet_launcher",
       sizeof(propertyKeys) / sizeof(propertyKeys[0]),
       propertyKeys,
@@ -339,76 +339,50 @@ void Launcher::Launch(const string& exe_path, const string& app_root, int argc,
       &domainId);
 
   _DBG("after initialize coreclr");
-#ifdef LAUNCHING_TIME_MEASURE
-  std::clock_t initialize_coreclr_time = std::clock();
-  _DBG("call coreclr_initialize ... : %Lf ms ", (initialize_coreclr_time - start) / (double)(CLOCKS_PER_SEC / 1000));
-#endif
   if (st < 0)
   {
     // initialize coreclr fail
     _ERR("initialize core clr fail! (0x%08x)", st);
     _DBG("check your smack label dll and every directories on the way to dlls");
+    return 1;
   }
-  else
+
+  struct stat sb;
+  if (stat(launcher_assembly.c_str(), &sb) == -1)
   {
-    unsigned int exitCode;
-    const char** argvc = const_cast<const char**>(argv);
-    st = executeAssembly(hostHandle, domainId, argc, argvc, exe_path.c_str(), &exitCode);
-    _DBG("after execute coreclr");
-    if (st < 0)
-    {
-      // execute coreclr fail
-      _ERR("execute core clr fail! (0x%08x / %d)", st, exitCode);
-    }
-    st = shutdownCoreCLR(hostHandle, domainId);
-    if (st < 0)
-    {
-      // shutdown fail
-      _ERR("shutdown core clr fail! (0x%08x)", st);
-    }
-#ifdef LAUNCHING_TIME_MEASURE
-    std::clock_t execute_assembly_time = std::clock();
-    _DBG("call execute_assembly_time ... : %Lf ms ", (execute_assembly_time - initialize_coreclr_time) / (double)(CLOCKS_PER_SEC / 1000));
-#endif
+    _ERR("Launcher assembly is not exist in %s", launcher_assembly.c_str());
+    return 1;
+  }
+
+  unsigned int exitCode;
+  const char** cargv = const_cast<const char**>(argv);
+  st = coreclr_execute_assembly(hostHandle, domainId,
+      argc, cargv, launcher_assembly.c_str(), &exitCode);
+  _DBG("after execute coreclr");
+  if (st < 0)
+  {
+    _ERR("execute core clr fail! (0x%08x / %d)", st, exitCode);
+    return 1;
   }
+
+  st = coreclr_shutdown(hostHandle, domainId);
+  if (st < 0)
+  {
+    _ERR("shutdown core clr fail! (0x%08x)", st);
+    return 1;
+  }
+
   if (dlclose(coreclrLib) != 0)
   {
     _ERR("libcoreclr.so close failed");
+    return 1;
   }
-#ifdef LAUNCHING_TIME_MEASURE
-    std::clock_t after_launching_time = std::clock();
-    _DBG("launching end time ... : %Lf ms ", (after_launching_time - start) / (double)(CLOCKS_PER_SEC / 1000));
-#endif
-}
-
-}  // namespace runtime
-}  // namespace dotnet
 
-using dotnet::runtime::Launcher;
-using dotnet::runtime::Waiter;
+  return 0;
+}
 
 int main(int argc, char *argv[])
 {
   _DBG("launcher started");
-
-  for (int i=0; i<argc; i++)
-  {
-    _DBG("argv[%d](%d) : [%s]", i, strlen(argv[i]), argv[i]);
-  }
-
-  std::unique_ptr<Launcher> launcher(new Launcher());
-  auto on_prepare = [&launcher]()
-  {
-    launcher->Initialize();
-  };
-  auto on_requested = [&launcher]()
-  {
-  };
-  auto on_executed = [&launcher](const std::string& path, const std::string& app_root, int argc, char *argv[])
-  {
-    _DBG("EXECUTE %s", path.c_str());
-    launcher->Launch(path, app_root, argc, argv);
-  };
-  std::unique_ptr<Waiter> waiter(new Waiter(on_prepare, on_requested, on_executed));
-  waiter->WaitToLaunching(argc, argv);
+  return RunLauncherDll(argc, argv);
 }
index acba908..4800ddf 100644 (file)
@@ -25,6 +25,24 @@ typedef int (*coreclr_shutdown_ptr)(
     void* hostHandle,
     unsigned int domainId);
 
+typedef int (*coreclr_create_delegate_ptr)(
+    void* hostHandle,
+    unsigned int domainId,
+    const char* entryPointAssemblyName,
+    const char* entryPointTypeName,
+    const char* entryPointMethodName,
+    void** delegate);
+
+typedef bool (*AssemblyManager_Initialize)(
+    const char* searchableDirectories,
+    const char* preloadDllPaths);
+
+typedef void (*AssemblyManager_AddAssemblyDir)(const char* dir); 
+typedef void (*AssemblyManager_RemoveAssemblyDir)(const char* dir); 
+
+typedef void (*AssemblyManager_Execute)(const char* dllPath);
+typedef void (*AssemblyManager_Finish)(void);
+
 using std::string;
 using std::vector;
 
@@ -34,18 +52,26 @@ class Launcher
     Launcher();
     ~Launcher();
     void Initialize();
-    void Launch(const string& exe_path, const string& app_root, int argc, char *argv[]);
 
   private:
     coreclr_initialize_ptr initializeCoreCLR;
-    coreclr_execute_assembly_ptr executeAssembly;
+//    coreclr_execute_assembly_ptr executeAssembly;
     coreclr_shutdown_ptr shutdownCoreCLR;
+    coreclr_create_delegate_ptr createDelegate;
 
     string TrustedPlatformAssemblies;
     string NativeDllSearchDirectories;
     string AppDomainCompatSwitch;
 
     void *coreclrLib;
+
+    AssemblyManager_Initialize assemblyManagerInitialize;
+    AssemblyManager_Execute assemblyManagerExecute;
+    AssemblyManager_Finish assemblyManagerFinish;
+    AssemblyManager_AddAssemblyDir assemblyManagerAddDir;
+    AssemblyManager_RemoveAssemblyDir assemblyManagerRemoveDir;
+
+    bool initialized;
 };
 
 }  // namespace runtime
index 6f83482..c7cb794 100644 (file)
@@ -30,16 +30,30 @@ static std::vector<pollfd> Fdlist_;
 static std::map<int, FdHandler> Handlers_;
 static Waiter::AppInfo AppInfo_;
 
-void Waiter::OnPrepare()
+void Waiter::OnPrepared()
 {
-  // preload the libraries.
-  if (prepare_ != nullptr)
-    prepare_();
+  if (!context.Prepare())
+  {
+    _DBG("Fail to Prepare...");
+  }
 }
 
-void Waiter::OnLaunchRequested(const AppInfo& info)
+void Waiter::OnRequested(const AppInfo& info)
 {
   // do some job on user id is still system
+
+  if (!context.Request())
+  {
+    _DBG("Fail to Request...");
+  }
+}
+
+void Waiter::OnExecuted(const char *path, const char *app_root, int argc, char *argv[])
+{
+  if (!context.Execute(path, app_root, argc, argv))
+  {
+    _DBG("Fail to Execute...");
+  }
 }
 
 void Waiter::OnWaiting()
@@ -98,18 +112,6 @@ void Waiter::DeregisterFd(int fd)
   Handlers_.erase(fd);
 }
 
-
-Waiter::Waiter(Action prepare, Action requested, Executor executor)
-{
-  prepare_ = prepare;
-  requested_ = requested;
-  executor_ = executor;
-}
-
-Waiter::~Waiter()
-{
-}
-
 int Waiter::WaitToLaunching(int argc, char *argv[])
 {
 #ifndef NO_TIZEN
@@ -117,7 +119,7 @@ int Waiter::WaitToLaunching(int argc, char *argv[])
   {
     _DBG("on_create..."); // XXX
     Waiter* waiter = static_cast<Waiter*>(user_data);
-    waiter->OnPrepare();
+    waiter->OnPrepared();
   };
 
   auto on_launch = [](int argc, char **argv, const char *app_path,
@@ -139,7 +141,7 @@ int Waiter::WaitToLaunching(int argc, char *argv[])
       PkgType : pkg_type
     };
 
-    waiter->OnLaunchRequested(info);
+    waiter->OnRequested(info);
     return 0;
   };
 
@@ -149,7 +151,7 @@ int Waiter::WaitToLaunching(int argc, char *argv[])
     
     string app_root(aul_get_app_root_path());
     Waiter* waiter = static_cast<Waiter*>(user_data);
-    waiter->executor_(argv[0], app_root, argc, argv);
+    waiter->OnExecuted(argv[0], app_root.c_str(), argc, argv);
     return 0;
   };
 
@@ -197,7 +199,12 @@ int Waiter::WaitToLaunching(int argc, char *argv[])
 
   return launchpad_loader_main(argc, argv, &callbacks, &adapter, this);
 #else
-  if (argc < 2) return -1;
+  if (argc < 2)
+  {
+    _DBG("not enough args : %d", argc);
+    return -1;
+  }
+  _DBG("argv[1] = %s", argv[1]);
   std::string app_path(argv[1]);
   std::string app_root;
   auto pos = app_path.find_last_of('/');
@@ -206,17 +213,83 @@ int Waiter::WaitToLaunching(int argc, char *argv[])
   else
     app_root = ".";
 
-  this->OnPrepare();
-    AppInfo info = {
-      AppPath : argv[1],
-      AppId : "",
-      PkgId : "",
-      PkgType : ""
-    };
-  this->OnLaunchRequested(info);
-  this->executor_(app_path, app_root, argc, argv);
+  this->OnPrepared();
+  AppInfo info = {
+    AppPath : argv[1],
+    AppId : "",
+    PkgId : "",
+    PkgType : ""
+  };
+  this->OnRequested(info);
+  this->OnExecuted(app_path.c_str(), app_root.c_str(), argc, argv);
 #endif
 }
 
+void Waiter::SetContext(WaiterContext ctx)
+{
+  context = ctx;
+}
+
+WaiterContext::WaiterContext()
+{
+  Step = Status::Started;
+}
+
+bool WaiterContext::Prepare()
+{
+  if (Step == Status::Started && Prepared != nullptr && Prepared(Data) == 0)
+  {
+    Step = Status::Prepared;
+    return true;
+  }
+  return false;
+}
+
+bool WaiterContext::Request()
+{
+  if (Step == Status::Prepared && Requested != nullptr && Requested(Data) == 0)
+  {
+    Step = Status::Requested;
+    return true;
+  }
+  return false;
+}
+
+bool WaiterContext::Execute(const char *path, const char *app_root, int argc, char *argv[])
+{
+  if (Step == Status::Requested && Executed != nullptr &&
+      Executed(path, app_root, argc, argv, Data))
+  {
+    Step = Status::Executed;
+    return true;
+  }
+  return false;
+}
+
 }  // namespace runtime
 }  // namespace dotnet
+
+using dotnet::runtime::Waiter;
+using dotnet::runtime::WaiterContext;
+
+static Waiter waiter;
+
+void register_launching_callback(prepared_callback prepared,
+    requested_callback requested, executed_callback executed, void *data)
+{
+  WaiterContext context;
+  context.Prepared = prepared;
+  context.Requested = requested;
+  context.Executed = executed;
+  context.Data = data;
+
+  waiter.SetContext(context);
+}
+
+void wait_for_launching(int argc, char *argv[])
+{
+  _DBG("wait_for_launching...");
+
+  waiter.WaitToLaunching(argc, argv);
+}
+
index f233317..c4b98fb 100644 (file)
@@ -1,13 +1,50 @@
 #include <string>
 #include <functional>
 
-using std::string;
+#include <iostream>
+
+extern "C" {
+  typedef int (*prepared_callback)(void *data);
+  typedef int (*requested_callback)(void *data);
+  typedef int (*executed_callback)(const char* path, const char* app_root, int argc, char *argv[], void *data);
+
+  void register_launching_callback(prepared_callback prepared,
+      requested_callback requested, executed_callback executed, void *data);
+  void wait_for_launching(int argc, char *argv[]);
+}
 
 namespace dotnet {
 namespace runtime {
 
+using std::string;
 using Receiver = std::function<void(int)>;
 
+enum Status
+{
+  Started,
+  Prepared,
+  Requested,
+  Executed
+};
+
+class WaiterContext
+{
+  public:
+    prepared_callback Prepared;
+    requested_callback Requested;
+    executed_callback Executed;
+
+    void *Data;
+
+    WaiterContext();
+    bool Prepare();
+    bool Request();
+    bool Execute(const char *path, const char *app_root, int argc, char *argv[]);
+
+  private:
+    Status Step;
+};
+
 class Waiter
 {
   public:
@@ -18,28 +55,22 @@ class Waiter
       string PkgId;
       string PkgType;
     };
-    using Action = std::function<void(void)>;
-    using Executor = std::function<void(const string&, const string&, int, char**)>;
-
-    Waiter(Action prepare, Action requested, Executor executor);
-    ~Waiter();
 
     int WaitToLaunching(int argc, char *argv[]);
     void Stop();
 
     void RegisterFd(int fd, Receiver receiver);
     void DeregisterFd(int fd);
+    void SetContext(WaiterContext ctx);
 
   protected:
-    void OnPrepare();
-    void OnLaunchRequested(const AppInfo&);
+    void OnPrepared();
+    void OnRequested(const AppInfo&);
     void OnWaiting();
+    void OnExecuted(const char *path, const char *app_root, int argc, char *argv[]);
 
   private:
-
-    Action prepare_; 
-    Action requested_;
-    Executor executor_;
+    WaiterContext context;
 };
 
 }  // namespace runtime
index f2484c1..8c1d628 100644 (file)
@@ -1,8 +1,8 @@
 <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
        
        <PropertyGroup>
-               <CoreFXRefPath>/opt/usr/share/tizen.net/ref</CoreFXRefPath>
-               <TizenDeviceAPIPath>/usr/share/assembly</TizenDeviceAPIPath>
+               <CoreFXRefPath Condition=" '$(CoreFXRefPath)' == '' ">/opt/usr/share/tizen.net/ref</CoreFXRefPath>
+               <TizenDeviceAPIPath Condition=" '$(TizenDeviceAPIPath)' == '' ">/usr/share/assembly</TizenDeviceAPIPath>
        </PropertyGroup>
 
        <PropertyGroup>
                <AdditionalLibPaths>$(CoreFXRefPath);$(TizenDeviceAPIPath)</AdditionalLibPaths>
                <AddAdditionalExplicitAssemblyReferences>false</AddAdditionalExplicitAssemblyReferences>
                <!-- Temporary suppress the warning... -->
-               <NoWarn>1701</NoWarn>
+               <NoWarn>1701, 1702</NoWarn>
+       </PropertyGroup>
+
+       <PropertyGroup>
+               <CscToolPath>$(ExternalCscDir)</CscToolPath>
+               <CscToolExe>$(ExternalCscExe)</CscToolExe>
        </PropertyGroup>
 
        <ItemGroup>
                <ReferencePath Include="@(TizenDeviceAPIAssemblies->'%(Filename).dll')"/>
        </ItemGroup>
 
-       <Target Name="BeforeBuild">
+       <Target Name="LogVariables" AfterTargets="Build">
                <Message Text="[CoreFX Reference Environment!]"/>
+               <Message Text="CscItem = %(ExternalCscPathItem.FullPath)"/>
+               <Message Text="CscPath = %(ExternalCscDirectory.FullPath)"/>
+               <Message Text="CscExe = %(ExternalCscExe.Identity)"/>
                <Message Text="CoreFX dir = $(CoreFXRefPath)"/>
                <Message Text="CoreFX dir Check Ok" Condition="Exists('$(CoreFXRefPath)')"/>
                <Message Text="Tizen Device API dir = $(TizenDeviceAPIPath)"/>
@@ -40,8 +48,4 @@
                <Message Text="CoreFXRefAssemblies = %(CoreFXRefAssemblies.Identity)"/>
                <Message Text="TizenDeviceAPIAssemblies = %(TizenDeviceAPIAssemblies.Identity)"/>
        </Target>
-
-       <PropertyGroup>
-               <CheckConfigDependsOn>CheckEnvironment</CheckConfigDependsOn>
-       </PropertyGroup>
 </Project>
index ffe4d9c..ed996ac 100644 (file)
@@ -4,7 +4,7 @@
        <PropertyGroup>
                <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
     <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <OutputType>Library</OutputType>
+    <OutputType>exe</OutputType>
                <AssemblyName>Tizen.Runtime</AssemblyName>
        </PropertyGroup>
 
     <DefineConstants>TRACE</DefineConstants>
        </PropertyGroup>
 
+<!-- Roslyn Not Support Assembly Signing yet.
        <PropertyGroup>
                <SignAssembly>true</SignAssembly>
                <AssemblyOriginatorKeyFile>Tizen.Runtime.snk</AssemblyOriginatorKeyFile>
        </PropertyGroup>
+-->
+
+       <PropertyGroup>
+               <DefineConstants Condition=" '$(CLOG)' != '' ">$(DefineConstants);CLOG</DefineConstants>
+       </PropertyGroup>
 
        <ItemGroup>
+               <Compile Include="Tizen.Runtime/AssemblyManager.cs" />
                <Compile Include="Tizen.Runtime/AssemblyLoader.cs" />
                <Compile Include="Tizen.Runtime/Log.cs" />
-               <Compile Include="Tizen.Runtime/AssemblyManager.cs" />
+               <Compile Include="Tizen.Runtime/Interop.cs" />
+               <Compile Include="Tizen.Runtime/Ini.cs" />
+               <Compile Include="Tizen.Runtime/DefaultConfigAttribute.cs" />
        </ItemGroup>
 
        <Target Name="CheckConfig">
                <Message Text="MSBuildProjectDirectory = $(MSBuildProjectDirectory)"/>
+
+               <ItemGroup>
+                       <AssemblyAttributes Include="DefaultConfigAttribute" Condition=" $(LauncherConfigPath) != '' ">
+                               <_Parameter1>ConfigPath=$(LauncherConfigPath)</_Parameter1>
+                       </AssemblyAttributes>
+               </ItemGroup>
+
+               <WriteCodeFragment AssemblyAttributes="@(AssemblyAttributes)"
+                       Language="C#"
+                       OutputDirectory="$(IntermediateOutputPath)"
+                       OutputFile="ConfigPath.cs">
+                       <Output TaskParameter="OutputFile" ItemName="Compile" />
+               </WriteCodeFragment>
+
        </Target>
 
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
        <Import Project="$(MSBuildProjectDirectory)/Tizen.CoreFX.Ref.Targets" />
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
 </Project>
index e959146..a80e781 100644 (file)
@@ -9,37 +9,80 @@ namespace Tizen.Runtime
     public class AssemblyLoader : AssemblyLoadContext
     {
         private SortedSet<string> _dllDirectories = new SortedSet<string>();
+        private SortedSet<string> _nativeDirectories = new SortedSet<string>();
+
         public IEnumerable<string> DllDirectories
         {
             get { return _dllDirectories; }
         }
 
+        public IEnumerable<string> NativeDirectories
+        {
+            get { return _nativeDirectories; }
+        }
+
         public void AddSearchableDirectory(string directory)
         {
             if (Directory.Exists(directory))
             {
                 _dllDirectories.Add(directory);
+                _nativeDirectories.Add(directory);
             }
         }
 
         public void RemoveSearchableDirectory(string directory)
         {
             _dllDirectories.Remove(directory);
+            _nativeDirectories.Remove(directory);
         }
 
         protected override Assembly Load(AssemblyName assemblyName)
         {
-            ALog.Debug($"Load!! : {assemblyName.Name}");
-            foreach (string dir in DllDirectories)
+            ALog.Debug($"Load DLL : {assemblyName.Name}");
+            Assembly asm = null;
+
+            try
+            {
+                asm = Assembly.Load(assemblyName);
+            }
+            catch (Exception ex)
+                when (ex is FileNotFoundException ||
+                        ex is BadImageFormatException ||
+                        ex is FileLoadException)
             {
-                FileInfo f = new FileInfo(Path.Combine(dir, $"{assemblyName.Name}.dll"));
-                ALog.Debug(f.FullName);
-                if (File.Exists(f.FullName))
+                ALog.Debug("Search DLL in added directories");
+                foreach (string dir in DllDirectories)
                 {
-                    return LoadFromAssemblyPath(f.FullName);
+                    FileInfo f = new FileInfo(Path.Combine(dir, $"{assemblyName.Name}.dll"));
+                    if (File.Exists(f.FullName))
+                    {
+                        asm = LoadFromAssemblyPath(f.FullName);
+                        break;
+                    }
                 }
             }
-            return Assembly.Load(assemblyName);
+            return asm;
+        }
+
+        protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
+        {
+            ALog.Debug($"Load Native : {unmanagedDllName}");
+            IntPtr native = base.LoadUnmanagedDll(unmanagedDllName);
+            if (native == IntPtr.Zero)
+            {
+                ALog.Debug("Search native lib in added directories");
+                foreach (string dir in NativeDirectories)
+                {
+                    FileInfo f = new FileInfo(Path.Combine(dir, unmanagedDllName));
+                    if (File.Exists(f.FullName))
+                    {
+                        native = LoadUnmanagedDllFromPath(f.FullName);
+                        break;
+                    }
+                }
+            }
+
+            return native;
         }
     }
 }
index f7a7810..1f50867 100644 (file)
 using System.IO;
 using System.Reflection;
 using System.Runtime.Loader;
+using System.Linq;
 
 namespace Tizen.Runtime
 {
     public static class AssemblyManager
     {
-        private static void PrintException(Exception exception)
+        public static int Prepared(IntPtr data)
         {
-            while (exception != null)
+            try
             {
-                ALog.Debug(exception.Message);
-                ALog.Debug(exception.StackTrace);
-                exception = exception.InnerException;
+                string configPath = "file:///etc/dotnet-launcher.ini";
+                ICustomAttributeProvider assembly = typeof(AssemblyManager).GetTypeInfo().Assembly;
+                var attributes = assembly.GetCustomAttributes(typeof(DefaultConfigAttribute), false);
+                if (attributes.Length > 0 && attributes[0] is DefaultConfigAttribute)
+                {
+                    DefaultConfigAttribute dca = (DefaultConfigAttribute)attributes[0];
+                    FileInfo f = new FileInfo(dca.Config["ConfigPath"]);
+                    if (File.Exists(f.FullName))
+                    {
+                        configPath = "file://"+f.FullName;
+                    }
+                }
+
+                Ini ini = new Ini(new Uri(configPath));
+                var dotnet = ini["dotnet"];
+                foreach(var kv in dotnet)
+                {
+                    ALog.Debug(kv.Key + " = " + kv.Value);
+                }
+
+                string preloadDlls = "";
+                string preloadDllDirs = "";
+                var preloads = ini["preloads"];
+                if (preloads != null)
+                {
+                    foreach (string key in preloads.Keys) 
+                    {
+                        FileInfo f = new FileInfo(key);
+                        if (File.Exists(f.FullName))
+                        {
+                            preloadDlls += f.FullName + ":";
+                            preloadDllDirs += f.Directory + ":";
+                        }
+                    }
+                }
+
+                if (!Initialize(preloadDllDirs, preloadDlls))
+                {
+                    return 1;
+                }
             }
+            catch(Exception e)
+            {
+                ALog.Debug("Exception at Preparing");
+                PrintException(e);
+                return 1;
+            }
+            return 0;
         }
 
-        public static AssemblyLoader CurrentAssemblyLoaderContext
+        public static int Requested(IntPtr data)
         {
-            get;
-            private set;
+            return 0;
+        }
+
+        public static int Executed(string path, string app_root, int argc, string[] argv, IntPtr data)
+        {
+            try
+            {
+                FileInfo f = new FileInfo(path);
+                CurrentAssemblyLoaderContext.AddSearchableDirectory(f.Directory.FullName);
+                DirectoryInfo d = new DirectoryInfo(app_root);
+                CurrentAssemblyLoaderContext.AddSearchableDirectory(d.FullName);
+                Execute(path);
+            }
+            catch(Exception e)
+            {
+                ALog.Debug("Exception at Executing");
+                PrintException(e);
+                return 1;
+            }
+
+            try
+            {
+                Finish();
+            }
+            catch(Exception e)
+            {
+                ALog.Debug("Exception at Finishing");
+                PrintException(e);
+                return 1;
+            }
+            return 0;
+        }
+
+        static Interop.PreparedCallback preparedCallback;
+        static Interop.RequestedCallback requestedCallback;
+        static Interop.ExecutedCallback executedCallback;
+
+        public static void Main(string[] args)
+        {
+            try
+            {
+                preparedCallback = Prepared;
+                requestedCallback = Requested;
+                executedCallback = Executed;
+                Interop.register_launching_callback(preparedCallback, requestedCallback, executedCallback, IntPtr.Zero);
+                Interop.wait_for_launching(args.Length, args);
+            }
+            catch(Exception e)
+            {
+                PrintException(e);
+            }
+        }
+
+        private static void PrintException(Exception exception)
+        {
+            while (exception != null)
+            {
+                ALog.Debug(exception.ToString());
+                exception = exception.InnerException;
+            }
         }
 
         public static bool Initialize(string searchableDirectories, string preloadDllPaths)
@@ -31,7 +134,7 @@ namespace Tizen.Runtime
 
                 if (searchableDirectories != null)
                 {
-                    string[] dirs = searchableDirectories.Split(':');
+                    string[] dirs = searchableDirectories.Split(new char[]{':'}, StringSplitOptions.None);
                     foreach (string dir in dirs)
                     {
                         CurrentAssemblyLoaderContext.AddSearchableDirectory(dir);
@@ -40,9 +143,10 @@ namespace Tizen.Runtime
 
                 if (preloadDllPaths != null)
                 {
-                    string[] dllPaths = preloadDllPaths.Split(':');
+                    string[] dllPaths = preloadDllPaths.Split(new char[]{':'}, StringSplitOptions.None);
                     foreach (string dllPath in dllPaths)
                     {
+                        if (string.IsNullOrWhiteSpace(dllPath)) continue;
                         FileInfo f = new FileInfo(dllPath);
                         if (File.Exists(f.FullName))
                         {
@@ -82,6 +186,24 @@ namespace Tizen.Runtime
 
         public static void Finish()
         {
+            ALog.Debug("-------- Dll Search Dir");
+            foreach (string dir in CurrentAssemblyLoaderContext.DllDirectories)
+            {
+                ALog.Debug(dir);
+            }
+
+            ALog.Debug("-------- Native Search Dir");
+            foreach (string dir in CurrentAssemblyLoaderContext.NativeDirectories)
+            {
+                ALog.Debug(dir);
+            }
+        }
+
+        public static AssemblyLoader CurrentAssemblyLoaderContext
+        {
+            get;
+            private set;
         }
+
     }
 }
diff --git a/Tizen.Runtime/Tizen.Runtime/DefaultConfigAttribute.cs b/Tizen.Runtime/Tizen.Runtime/DefaultConfigAttribute.cs
new file mode 100644 (file)
index 0000000..f5ba0b0
--- /dev/null
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+
+[AttributeUsage(AttributeTargets.Assembly)]
+public class DefaultConfigAttribute : Attribute {
+    public DefaultConfigAttribute() : this(string.Empty) {}
+    public DefaultConfigAttribute(string txt)
+    {
+        Config = new Dictionary<string, string>();
+        string[] keyvalues = txt.Split(new string[] {","}, StringSplitOptions.None);
+        foreach (string kvstr in keyvalues)
+        {
+            int eq_pos = kvstr.IndexOf('=');
+            if (eq_pos == -1)
+                throw new FormatException("Config must be written like \"Key1=Value1, Key2=Value2\"");
+
+            string key = kvstr.Substring(0, eq_pos).Trim();
+            string value = kvstr.Substring(eq_pos+1).Trim();
+            Config[key] = value;
+        }
+    }
+    public Dictionary<string, string> Config
+    {
+        get;
+        set;
+    }
+}
diff --git a/Tizen.Runtime/Tizen.Runtime/Ini.cs b/Tizen.Runtime/Tizen.Runtime/Ini.cs
new file mode 100644 (file)
index 0000000..d5c2544
--- /dev/null
@@ -0,0 +1,139 @@
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Tizen.Runtime
+{
+    internal class Ini
+    {
+        public string GlobalName = "___GLOBAL";
+        public Ini(Uri path)
+        {
+            if (path.Scheme != "file")
+            {
+                throw new NotSupportedException("Only File Uri is supported now");
+            }
+            string absPath = path.AbsolutePath;
+            Initialize();
+            Contents = File.ReadAllText(absPath);
+        }
+
+        public Ini(string contents)
+        {
+            Initialize();
+            Contents = contents;
+        }
+
+        public string Contents
+        {
+            get { return contents; }
+            
+            set
+            {
+                contents = value;
+                ReadContents(contents);
+            }
+        }
+
+        public Dictionary<string, string> this[string name]
+        {
+            get
+            {
+                if (groups.ContainsKey(name))
+                    return groups[name];
+                return null;
+            }
+        }
+
+        public override string ToString()
+        {
+            string str = "";
+
+            if (groups.ContainsKey(GlobalName))
+            {
+                foreach (var kv in groups[GlobalName])
+                {
+                    str += $"{kv.Key} = {kv.Value}" + Environment.NewLine;
+                }
+            }
+
+            foreach (var gkv in groups)
+            {
+                if (gkv.Key == GlobalName) continue;
+                str += $"[{gkv.Key}]" + Environment.NewLine;
+                foreach (var kv in gkv.Value)
+                {
+                    str += $"{kv.Key} = {kv.Value}" + Environment.NewLine;
+                }
+            }
+
+            return str;
+        }
+
+        public Dictionary<string, string> Global
+        {
+            get
+            {
+                return groups[GlobalName];
+            }
+        }
+
+        private void Initialize()
+        {
+            groups = new Dictionary<string, Dictionary<string, string> >();
+            groups[GlobalName] = new Dictionary<string, string>();
+        }
+
+        private string Uncommont(string str)
+        {
+            int comment_start = str.IndexOf('#');
+            return str.Substring(0, comment_start);
+        }
+
+        private bool GetHeader(string str, ref string groupName)
+        {
+            if (str.Length < 2 || str[0] != '[' || str[str.Length-1] != ']') return false;
+            string expected = str.Substring(1, str.Length-2);
+            groupName = expected.Trim();
+            return true;
+        }
+
+        private void GetKeyValueFromString(string str, out string key, out string value)
+        {
+            int eq_pos = str.IndexOf('=');
+            if (eq_pos == -1)
+            {
+                key = str.Trim();
+                value = "";
+            }
+            else
+            {
+                key = str.Substring(0, eq_pos).Trim();
+                value = str.Substring(eq_pos+1).Trim();
+            }
+        }
+
+        private void ReadContents(string contents)
+        {
+            string key, value;
+            string groupName = GlobalName;
+            string[] lines = contents.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
+
+            foreach (string line in lines)
+            {
+                if (string.IsNullOrWhiteSpace(line)) continue;
+                if (GetHeader(line, ref groupName))
+                {
+                    groups[groupName] = new Dictionary<string, string>();
+                    continue;
+                }
+                GetKeyValueFromString(line, out key, out value);
+                groups[groupName][key] = value;
+            }
+        }
+
+        private Dictionary<string, Dictionary<string, string> > groups;
+        private string contents;
+    }
+}
diff --git a/Tizen.Runtime/Tizen.Runtime/Interop.cs b/Tizen.Runtime/Tizen.Runtime/Interop.cs
new file mode 100644 (file)
index 0000000..3476a81
--- /dev/null
@@ -0,0 +1,20 @@
+using System;
+using System.Runtime.InteropServices;
+
+internal static class Interop
+{
+    public const string Launcher = "dotnet-launcher";
+
+    internal delegate int PreparedCallback(IntPtr userData);
+    internal delegate int RequestedCallback(IntPtr userData);
+    internal delegate int ExecutedCallback(string path, string app_root, int argc, string[] argv, IntPtr userData);
+
+    [DllImport(Launcher)]
+    internal static extern void register_launching_callback(
+            [MarshalAs(UnmanagedType.FunctionPtr)] PreparedCallback prepared,
+            [MarshalAs(UnmanagedType.FunctionPtr)] RequestedCallback requested,
+            [MarshalAs(UnmanagedType.FunctionPtr)] ExecutedCallback executed, IntPtr userData);
+
+    [DllImport(Launcher)]
+    internal static extern void wait_for_launching(int argc, string[] argv);
+}
index 353ab99..883fae0 100644 (file)
@@ -43,6 +43,7 @@ Launchpad plugin for launching dotnet apps
 cmake \
        -DCMAKE_INSTALL_PREFIX=%{_prefix} \
        -DPACKAGE_NAME=%{name} \
+       -DLIBDIR=%{_libdir} \
        -DBINDIR=%{_bindir} \
        -DLOADERDIR=%{_loaderdir} \
        -DCONFIGDIR=%{_configdir} \
@@ -57,11 +58,12 @@ xbuild /p:Configuration=%{_buildmode} Tizen.Runtime/Tizen.Runtime.csproj
 %install
 rm -rf %{buildroot}
 %make_install
-install -p -m 644 Tizen.Runtime/bin/Tizen.Runtime.dll %{buildroot}%{_bindir}
+install -p -m 644 Tizen.Runtime/bin/Tizen.Runtime.exe %{buildroot}%{_bindir}
 
 %files
 %manifest dotnet-launcher.manifest
 %config /etc/dotnet-launcher.ini
 %{_loaderdir}/dotnet.loader
 %caps(cap_mac_admin,cap_setgid=ei) %{_bindir}/dotnet-launcher
-%caps(cap_mac_admin,cap_setgid=ei) %{_bindir}/Tizen.Runtime.dll
+%caps(cap_mac_admin,cap_setgid=ei) %{_libdir}/libdnclauncher.so
+%caps(cap_mac_admin,cap_setgid=ei) %{_bindir}/Tizen.Runtime.exe
diff --git a/test_build_on_desktop.sh b/test_build_on_desktop.sh
new file mode 100755 (executable)
index 0000000..90a8583
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+#CoreFXRefPath=`readlink -e ../dlls/corefx_refs/`
+#TizenDeviceAPIPath=`readlink -e ../dlls/tizen_deviceapis/`
+CoreFXRefPath=`readlink -e ../dlls/desktop/`
+TizenDeviceAPIPath=`readlink -e ../dlls/tizen_deviceapis/`
+LauncherConfigPath=./dotnet-launcher.ini
+RoslynCscDir=/home/idkiller/work/runtime/roslyn/Binaries/Debug/csccore
+RoslynCscExe=csc
+
+mkdir build
+cd build
+cmake -DCMAKE_BUILD_TYPE=Debug -DNO_TIZEN=1 -DLAUNCHER_CONFIG_PATH=$LauncherConfigPath -DLAUNCHER_ASSEMBLY_PATH=Tizen.Runtime.dll ../NativeLauncher/
+make
+xbuild /t:Clean ../Tizen.Runtime/Tizen.Runtime.csproj
+#xbuild /verbosity:diagnostic /p:CLOG=1 /p:ExternalCscPath=/home/idkiller/work/runtime/roslyn/Binaries/Debug/csccore/csc.exe /p:LauncherConfigPath=$LauncherConfigPath /p:CoreFXRefPath=$CoreFXRefPath /p:TizenDeviceAPIPath=$TizenDeviceAPIPath ../Tizen.Runtime/Tizen.Runtime.csproj
+xbuild /p:CLOG=1 /p:ExternalCscDir=$RoslynCscDir /p:ExternalCscExe=$RoslynCscExe /p:LauncherConfigPath=$LauncherConfigPath /p:CoreFXRefPath=$CoreFXRefPath /p:TizenDeviceAPIPath=$TizenDeviceAPIPath ../Tizen.Runtime/Tizen.Runtime.csproj
+cp ../Tizen.Runtime/bin/Tizen.Runtime.* .
+cp ../NativeLauncher/dotnet-launcher.ini .