diff --git a/boosthost/CMakeLists.txt b/boosthost/CMakeLists.txt index 9771c4f94..1eb5c5d82 100644 --- a/boosthost/CMakeLists.txt +++ b/boosthost/CMakeLists.txt @@ -1,2 +1,4 @@ cmake_minimum_required(VERSION 2.8.6) project(MOZARTBOOSTHOST CXX) + +add_subdirectory(emulator) diff --git a/boosthost/emulator/CMakeLists.txt b/boosthost/emulator/CMakeLists.txt new file mode 100644 index 000000000..7b96a261d --- /dev/null +++ b/boosthost/emulator/CMakeLists.txt @@ -0,0 +1,59 @@ +# Configure paths +set(MOZART_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../..") +set(MOZART_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/../..") + +# Configure compiler +set(CMAKE_CXX_FLAGS "-Wall -std=c++0x ${CMAKE_CXX_FLAGS}") + +if(WIN32) + # Boost requires this + add_definitions(-D_WIN32_WINNT=0x0501) +endif() + +# Boost library + +set(MOZART_BOOST_USE_STATIC_LIBS ON + CACHE BOOL "Use the static libraries of Boost") + +if(${MOZART_BOOST_USE_STATIC_LIBS}) + set(Boost_USE_STATIC_LIBS ON) +endif() + +find_package(Boost COMPONENTS + program_options system thread filesystem chrono REQUIRED) + +link_directories(${Boost_LIBRARY_DIRS}) +include_directories(${Boost_INCLUDE_DIRS}) + +if(MINGW) + # Work around a bug in MinGW + string(REGEX REPLACE "(^| )-std=c\\+\\+0x($| )" " -std=gnu++0x " + CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") +endif() + +# Mozart VM library + +include_directories("${MOZART_DIR}/vm/vm/main" "${MOZART_BUILD_DIR}/vm/vm/main") + +# Mozart VM Boost environment library + +include_directories("${MOZART_DIR}/vm/boostenv/main" + "${MOZART_BUILD_DIR}/vm/boostenv/main") + + +# Compile the executable +if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + include_directories(/usr/lib/c++/v1) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") +endif() + +add_executable(ozemulator emulator.cc) +target_link_libraries(ozemulator mozartvmboost mozartvm ${Boost_LIBRARIES}) + +if(NOT MINGW) + target_link_libraries(ozemulator pthread) +endif() + +# Install +install(TARGETS ozemulator DESTINATION bin) +install(PROGRAMS ozengine ozc DESTINATION bin) diff --git a/boosthost/emulator/emulator.cc b/boosthost/emulator/emulator.cc new file mode 100644 index 000000000..56ccac428 --- /dev/null +++ b/boosthost/emulator/emulator.cc @@ -0,0 +1,260 @@ +// Copyright © 2012, Université catholique de Louvain +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include +#include + +#include +#include +#include +#include + +using namespace mozart; +namespace fs = boost::filesystem; +namespace po = boost::program_options; + +std::string envVarToOptionName(const std::string& varName) { + if ((varName == "OZ_HOME") || (varName == "OZHOME")) + return "home"; + else + return ""; +} + +atom_t strToAtom(VM vm, const std::string& str) { + auto mozartStr = toUTF(makeLString(str.c_str(), str.size())); + return vm->getAtom(mozartStr.length, mozartStr.string); +} + +atom_t pathToAtom(VM vm, const fs::path& path) { + return strToAtom(vm, path.native()); +} + +int main(int argc, char** argv) { + // CONFIGURATION VARIABLES + + fs::path ozHome, initFunctorPath, baseFunctorPath; + std::string ozSearchPath, ozSearchLoad, appURL; + std::vector appArgs; + bool appGUI; + + // DEFINE OPTIONS + + po::options_description generic("Generic options"); + generic.add_options() + ("help", "produce help message"); + + po::options_description config("Configuration"); + config.add_options() + ("home", po::value(&ozHome), + "path to the home of the installation") + ("init", po::value(&initFunctorPath), + "path to the Init.ozf functor") + ("search-path", po::value(&ozSearchPath), + "search path") + ("search-load", po::value(&ozSearchLoad), + "search load") + ("gui", "GUI mode"); + + po::options_description hidden("Hidden options"); + hidden.add_options() + ("base", po::value(&baseFunctorPath), + "path to the Base.ozf functor") + ("app-url", po::value(&appURL), + "application URL") + ("app-args", po::value>(&appArgs), + "application arguments"); + + po::options_description cmdline_options; + cmdline_options.add(generic).add(config).add(hidden); + + po::options_description environment_options; + environment_options.add(config); + + po::options_description visible_options("Allowed options"); + visible_options.add(generic).add(config); + + po::positional_options_description positional_options; + positional_options.add("app-url", 1); + positional_options.add("app-args", -1); + + // PARSE OPTIONS + + po::variables_map varMap; + po::store(po::command_line_parser(argc, argv) + .options(cmdline_options) + .positional(positional_options) + .run(), + varMap); + po::store(po::parse_environment(environment_options, &envVarToOptionName), + varMap); + po::notify(varMap); + + // READ OPTIONS + + if (varMap.count("help") != 0) { + std::cout << visible_options << "\n"; + return 0; + } + + // Hacky way to guess if we are in a build setting + fs::path appPath = fs::path(argv[0]).parent_path(); + bool isBuildSetting = appPath.filename() == "emulator"; + + if (ozHome.empty()) { + if (isBuildSetting) + ozHome = appPath.parent_path().parent_path(); + else + ozHome = appPath.parent_path(); + + if (ozHome.empty()) + ozHome = "."; + } + + if (initFunctorPath.empty()) { + if (isBuildSetting) + initFunctorPath = ozHome / "lib" / "cache" / "Init.ozf"; + else + initFunctorPath = ozHome / "share" / "mozart" / "cache" / "Init.ozf"; + } + + bool useBaseFunctor = varMap.count("base") != 0; + + appGUI = varMap.count("gui") != 0; + + // SET UP THE VM AND RUN + + boostenv::BoostBasedVM boostBasedVM; + VM vm = boostBasedVM.vm; + + // Set some properties + { + auto& properties = vm->getPropertyRegistry(); + + atom_t ozHomeAtom = pathToAtom(vm, ozHome); + properties.registerValueProp( + vm, MOZART_STR("oz.home"), ozHomeAtom); + properties.registerValueProp( + vm, MOZART_STR("oz.emulator.home"), ozHomeAtom); + properties.registerValueProp( + vm, MOZART_STR("oz.configure.home"), ozHomeAtom); + + if (varMap.count("search-path") != 0) + properties.registerValueProp( + vm, MOZART_STR("oz.search.path"), strToAtom(vm, ozSearchPath)); + if (varMap.count("search-load") != 0) + properties.registerValueProp( + vm, MOZART_STR("oz.search.load"), strToAtom(vm, ozSearchLoad)); + + auto decodedURL = toUTF(makeLString(appURL.c_str())); + auto appURLAtom = vm->getAtom(decodedURL.length, decodedURL.string); + properties.registerValueProp( + vm, MOZART_STR("application.url"), appURLAtom); + + OzListBuilder argsBuilder(vm); + for (auto& arg: appArgs) { + auto decodedArg = toUTF(makeLString(arg.c_str())); + argsBuilder.push_back(vm, vm->getAtom(decodedArg.length, decodedArg.string)); + } + properties.registerValueProp( + vm, MOZART_STR("application.args"), argsBuilder.get(vm)); + + properties.registerValueProp( + vm, MOZART_STR("application.gui"), appGUI); + } + + // Load the Base environment is required + if (useBaseFunctor) { + UnstableNode baseEnv = OptVar::build(vm); + + vm->getPropertyRegistry().registerConstantProp( + vm, MOZART_STR("internal.boot.base"), baseEnv); + + UnstableNode baseValue; + auto& bootLoader = boostBasedVM.getBootLoader(); + + if (!bootLoader(vm, baseFunctorPath.native(), baseValue)) { + std::cerr << "panic: could not load Base functor at " + << baseFunctorPath << std::endl; + return 1; + } + + // Create the thread that loads the Base environment + if (Callable(baseValue).isProcedure(vm)) { + ozcalls::asyncOzCall(vm, baseValue, baseEnv); + } else { + // Assume it is a functor that does not import anything + UnstableNode applyAtom = build(vm, MOZART_STR("apply")); + UnstableNode applyProc = Dottable(baseValue).dot(vm, applyAtom); + UnstableNode importParam = build(vm, MOZART_STR("import")); + ozcalls::asyncOzCall(vm, applyProc, importParam, baseEnv); + } + + boostBasedVM.run(); + } + + // Load the Init functor + { + UnstableNode initFunctor = OptVar::build(vm); + + vm->getPropertyRegistry().registerConstantProp( + vm, MOZART_STR("internal.boot.init"), initFunctor); + + UnstableNode initValue; + auto& bootLoader = boostBasedVM.getBootLoader(); + + if (!bootLoader(vm, initFunctorPath.native(), initValue)) { + std::cerr << "panic: could not load Init functor at " + << initFunctorPath << std::endl; + return 1; + } + + // Create the thread that loads the Init functor + if (Callable(initValue).isProcedure(vm)) { + ozcalls::asyncOzCall(vm, initValue, initFunctor); + boostBasedVM.run(); + } else { + // Assume it is already the Init functor + DataflowVariable(initFunctor).bind(vm, initValue); + } + } + + // Apply the Init functor + { + UnstableNode InitFunctor; + vm->getPropertyRegistry().get( + vm, MOZART_STR("internal.boot.init"), InitFunctor); + + auto ApplyAtom = build(vm, MOZART_STR("apply")); + auto ApplyProc = Dottable(InitFunctor).dot(vm, ApplyAtom); + + auto BootModule = vm->findBuiltinModule(MOZART_STR("Boot")); + auto ImportRecord = buildRecord( + vm, buildArity(vm, MOZART_STR("import"), MOZART_STR("Boot")), + BootModule); + + ozcalls::asyncOzCall(vm, ApplyProc, ImportRecord, OptVar::build(vm)); + + boostBasedVM.run(); + } +} diff --git a/boosthost/emulator/ozc b/boosthost/emulator/ozc new file mode 100644 index 000000000..5ba8a970a --- /dev/null +++ b/boosthost/emulator/ozc @@ -0,0 +1,17 @@ +#!/bin/sh + +# where Oz resides: + +howcalled="$0" +cmd=`basename "$howcalled"` + +if test -z "${OZHOME}" +then + dir=`dirname "$howcalled"` + OZHOME=`(cd "$dir"; cd ..; /bin/pwd)` +fi +export OZHOME + +"$OZHOME/bin/ozemulator" \ + --base "$OZHOME/share/mozart/cache/Base.ozf" \ + -- "x-oz://system/Compile.ozf" "$@" diff --git a/boosthost/emulator/ozengine b/boosthost/emulator/ozengine new file mode 100644 index 000000000..bae8ca6d1 --- /dev/null +++ b/boosthost/emulator/ozengine @@ -0,0 +1,17 @@ +#!/bin/sh + +# where Oz resides: + +howcalled="$0" +cmd=`basename "$howcalled"` + +if test -z "${OZHOME}" +then + dir=`dirname "$howcalled"` + OZHOME=`(cd "$dir"; cd ..; /bin/pwd)` +fi +export OZHOME + +"$OZHOME/bin/ozemulator" \ + --base "$OZHOME/share/mozart/cache/Base.ozf" \ + -- "$@"