Commit e2e814e3 authored by Robert Kimball's avatar Robert Kimball Committed by Scott Cyphers

Fix build for MacOS (#1112)

* remove reference to ngraph core code from codegen. add stand-alone implementations of needed funcions

* fixed potential pointer leak

* clean up file_util

* more file util cleanup, removing unused functions

* interpreter works on mac

* CPU and INTERPRETER build and pass unmit tests on macos

* move get_directory to file_util

* cleanup
parent d18a9faf
......@@ -52,9 +52,11 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
set(MKLPACKAGE "mklml_mac_${MKLVERSION}.tgz")
set(MKL_SHA1_HASH d76083fd5a79767a96572ad0e23e7f4c892818f2)
set(MKL_LIBS libmklml.dylib libiomp5.dylib)
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
set(MKLPACKAGE "mklml_win_${MKLVERSION}.tgz")
set(MKL_SHA1_HASH d607ca92d7bfc101f0828c0b005098b75531669b)
set(MKL_LIBS mklml.dll libiomp5md.dll)
endif()
set(MKLURL ${MKLURLROOT}${MKLPACKAGE})
......
......@@ -204,12 +204,6 @@ endif()
target_include_directories(ngraph PUBLIC "${NGRAPH_INCLUDE_PATH}")
target_link_libraries(ngraph PUBLIC dl pthread)
if (APPLE)
set_property(TARGET ngraph PROPERTY PREFIX "lib")
set_property(TARGET ngraph PROPERTY OUTPUT_NAME "ngraph.so")
set_property(TARGET ngraph PROPERTY SUFFIX "")
endif()
#-----------------------------------------------------------------------------------------------
# Installation logic...
#-----------------------------------------------------------------------------------------------
......
......@@ -75,9 +75,8 @@ add_custom_target(header_resource
if (NGRAPH_CPU_ENABLE OR NGRAPH_GPU_ENABLE)
add_library(codegen SHARED ${SRC})
set_target_properties(codegen PROPERTIES VERSION ${NGRAPH_VERSION} SOVERSION ${NGRAPH_API_VERSION})
add_dependencies(codegen header_resource)
add_dependencies(codegen header_resource libmkldnn libeigen)
target_include_directories(codegen SYSTEM PUBLIC ${CMAKE_BINARY_DIR})
target_link_libraries(codegen PRIVATE libllvm)
target_link_libraries(codegen PUBLIC libmkldnn libeigen pthread dl)
target_link_libraries(codegen PRIVATE libllvm ngraph)
install(TARGETS codegen DESTINATION ${NGRAPH_INSTALL_LIB})
endif()
......@@ -49,7 +49,6 @@
#include "header_resource.hpp"
#include "ngraph/codegen/compiler.hpp"
#include "ngraph/file_util.hpp"
#include "ngraph/log.hpp"
#include "ngraph/util.hpp"
#if defined(__clang__)
......@@ -273,6 +272,7 @@ void codegen::StaticCompiler::add_header_search_path(const string& p)
}
}
}
std::unique_ptr<codegen::Module>
codegen::StaticCompiler::compile(std::unique_ptr<clang::CodeGenAction>& m_compiler_action,
const string& source)
......
......@@ -34,8 +34,9 @@
#include "ngraph/log.hpp"
using namespace std;
using namespace ngraph;
std::string ngraph::file_util::get_file_name(const std::string& s)
string file_util::get_file_name(const string& s)
{
string rc = s;
auto pos = s.find_last_of('/');
......@@ -46,7 +47,7 @@ std::string ngraph::file_util::get_file_name(const std::string& s)
return rc;
}
std::string ngraph::file_util::get_file_ext(const std::string& s)
string file_util::get_file_ext(const string& s)
{
string rc = get_file_name(s);
auto pos = rc.find_last_of('.');
......@@ -61,7 +62,18 @@ std::string ngraph::file_util::get_file_ext(const std::string& s)
return rc;
}
string ngraph::file_util::path_join(const string& s1, const string& s2)
string file_util::get_directory(const string& s)
{
string rc = s;
auto pos = s.find_last_of('/');
if (pos != string::npos)
{
rc = s.substr(0, pos);
}
return rc;
}
string file_util::path_join(const string& s1, const string& s2)
{
string rc;
if (s2.size() > 0)
......@@ -91,20 +103,20 @@ string ngraph::file_util::path_join(const string& s1, const string& s2)
return rc;
}
size_t ngraph::file_util::get_file_size(const string& filename)
size_t file_util::get_file_size(const string& filename)
{
// ensure that filename exists and get its size
struct stat stats;
if (stat(filename.c_str(), &stats) == -1)
{
throw std::runtime_error("Could not find file: \"" + filename + "\"");
throw runtime_error("Could not find file: \"" + filename + "\"");
}
return stats.st_size;
}
void ngraph::file_util::remove_directory(const string& dir)
void file_util::remove_directory(const string& dir)
{
struct stat status;
if (stat(dir.c_str(), &status) != -1)
......@@ -125,12 +137,12 @@ void ngraph::file_util::remove_directory(const string& dir)
}
}
void ngraph::file_util::remove_file(const string& file)
void file_util::remove_file(const string& file)
{
remove(file.c_str());
}
bool ngraph::file_util::make_directory(const string& dir)
bool file_util::make_directory(const string& dir)
{
if (mkdir(dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH))
{
......@@ -139,28 +151,12 @@ bool ngraph::file_util::make_directory(const string& dir)
// not really an error, the directory already exists
return false;
}
throw std::runtime_error("error making directory " + dir + " " + strerror(errno));
throw runtime_error("error making directory " + dir + " " + strerror(errno));
}
return true;
}
string ngraph::file_util::make_temp_directory(const string& path)
{
string fname = path.empty() ? file_util::get_temp_directory() : path;
string tmp_template = file_util::path_join(fname, "ngraph_XXXXXX");
char* tmpname = strdup(tmp_template.c_str());
string rc;
if (mkdtemp(tmpname))
{
rc = tmpname;
}
free(tmpname);
return rc;
}
std::string ngraph::file_util::get_temp_directory()
string file_util::get_temp_directory_path()
{
const vector<string> potential_tmps = {"NGRAPH_TMP", "TMPDIR", "TMP", "TEMP", "TEMPDIR"};
......@@ -181,12 +177,10 @@ std::string ngraph::file_util::get_temp_directory()
return path;
}
vector<char> ngraph::file_util::read_file_contents(const string& path)
vector<char> file_util::read_file_contents(const string& path)
{
size_t file_size = get_file_size(path);
vector<char> data;
data.reserve(file_size);
data.resize(file_size);
vector<char> data(file_size);
FILE* f = fopen(path.c_str(), "rb");
if (f)
......@@ -204,50 +198,28 @@ vector<char> ngraph::file_util::read_file_contents(const string& path)
}
else
{
throw std::runtime_error("error opening file '" + path + "'");
throw runtime_error("error opening file '" + path + "'");
}
return data;
}
std::string ngraph::file_util::read_file_to_string(const std::string& path)
string file_util::read_file_to_string(const string& path)
{
std::ifstream f(path);
std::stringstream ss;
ifstream f(path);
stringstream ss;
ss << f.rdbuf();
return ss.str();
}
void ngraph::file_util::iterate_files(const string& path,
std::function<void(const string& file, bool is_dir)> func,
static void iterate_files_worker(const string& path,
function<void(const string& file, bool is_dir)> func,
bool recurse)
{
vector<string> files;
vector<string> dirs;
file_util::iterate_files_worker(path,
[&files, &dirs](const string& file, bool is_dir) {
if (is_dir)
dirs.push_back(file);
else
files.push_back(file);
},
recurse);
for (auto f : files)
{
func(f, false);
}
for (auto f : dirs)
{
func(f, true);
}
}
void ngraph::file_util::iterate_files_worker(
const string& path, std::function<void(const string& file, bool is_dir)> func, bool recurse)
{
DIR* dir;
struct dirent* ent;
if ((dir = opendir(path.c_str())) != nullptr)
{
try
{
while ((ent = readdir(dir)) != nullptr)
{
......@@ -260,7 +232,7 @@ void ngraph::file_util::iterate_files_worker(
string dir_path = file_util::path_join(path, name);
if (recurse)
{
iterate_files(dir_path, func, recurse);
file_util::iterate_files(dir_path, func, recurse);
}
func(dir_path, true);
}
......@@ -275,18 +247,54 @@ void ngraph::file_util::iterate_files_worker(
default: break;
}
}
}
catch (...)
{
exception_ptr p = current_exception();
closedir(dir);
rethrow_exception(p);
}
closedir(dir);
}
else
{
throw std::runtime_error("error enumerating file " + path);
throw runtime_error("error enumerating file " + path);
}
}
string ngraph::file_util::tmp_filename(const string& extension)
void file_util::iterate_files(const string& path,
function<void(const string& file, bool is_dir)> func,
bool recurse)
{
vector<string> files;
vector<string> dirs;
iterate_files_worker(path,
[&files, &dirs](const string& file, bool is_dir) {
if (is_dir)
{
dirs.push_back(file);
}
else
{
files.push_back(file);
}
},
recurse);
for (auto f : files)
{
func(f, false);
}
for (auto f : dirs)
{
func(f, true);
}
}
string file_util::tmp_filename(const string& extension)
{
string tmp_template =
file_util::path_join(file_util::get_temp_directory(), "ngraph_XXXXXX" + extension);
file_util::path_join(file_util::get_temp_directory_path(), "ngraph_XXXXXX" + extension);
char* tmpname = strdup(tmp_template.c_str());
// mkstemp opens the file with open() so we need to close it
......@@ -297,53 +305,8 @@ string ngraph::file_util::tmp_filename(const string& extension)
return rc;
}
void ngraph::file_util::touch(const std::string& filename)
{
// inspired by http://chris-sharpe.blogspot.com/2013/05/better-than-systemtouch.html
int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_NOCTTY | O_NONBLOCK, 0666);
assert(fd >= 0);
close(fd);
// update timestamp for filename
int rc = utimes(filename.c_str(), nullptr);
assert(!rc);
}
bool ngraph::file_util::exists(const std::string& filename)
bool file_util::exists(const string& filename)
{
struct stat buffer;
return (stat(filename.c_str(), &buffer) == 0);
}
int ngraph::file_util::try_get_lock(const std::string& filename)
{
mode_t m = umask(0);
int fd = open(filename.c_str(), O_RDWR | O_CREAT, 0666);
umask(m);
if (fd >= 0 && flock(fd, LOCK_EX | LOCK_NB) < 0)
{
close(fd);
fd = -1;
}
return fd;
}
void ngraph::file_util::release_lock(int fd, const std::string& filename)
{
if (fd >= 0)
{
remove_file(filename);
close(fd);
}
}
time_t ngraph::file_util::get_timestamp(const std::string& filename)
{
time_t rc = 0;
struct stat st;
if (stat(filename.c_str(), &st) == 0)
{
rc = st.st_mtime;
}
return rc;
}
......@@ -22,35 +22,73 @@
namespace ngraph
{
class file_util;
}
namespace file_util
{
// @brief Returns the name with extension for a given path
// @param path The path to the output file
std::string get_file_name(const std::string& path);
class ngraph::file_util
{
public:
static std::string get_file_name(const std::string&);
static std::string get_file_ext(const std::string&);
static std::string path_join(const std::string& s1, const std::string& s2);
static size_t get_file_size(const std::string& filename);
static void remove_directory(const std::string& dir);
static bool make_directory(const std::string& dir);
static std::string make_temp_directory(const std::string& path = "");
static std::string get_temp_directory();
static void remove_file(const std::string& file);
static std::vector<char> read_file_contents(const std::string& path);
static std::string read_file_to_string(const std::string& path);
static void iterate_files(const std::string& path,
std::function<void(const std::string& file, bool is_dir)> func,
bool recurse = false);
static std::string tmp_filename(const std::string& extension = "");
static void touch(const std::string& filename);
static bool exists(const std::string& filename);
static int try_get_lock(const std::string& filename);
static void release_lock(int fd, const std::string& filename);
static time_t get_timestamp(const std::string& filename);
private:
static void iterate_files_worker(const std::string& path,
// @brief Returns the file extension
// @param path The path to the output file
std::string get_file_ext(const std::string& path);
// @brief Returns the directory portion of the given path
// @param path The path to the output file
std::string get_directory(const std::string& path);
// @brief Serialize a Function to as a json file
// @param s1 Left side of path
// @param s2 Right side of path
std::string path_join(const std::string& s1, const std::string& s2);
// @brief Returns the size in bytes of filename
// @param filename The name of the file
size_t get_file_size(const std::string& filename);
// @brief Removes all files and directories starting at dir
// @param dir The path of the directory to remove
void remove_directory(const std::string& dir);
// @brief Create a directory
// @param dir Path of the directory to create
// @param func The Function to serialize
// @return true if the directory was created, false otherwise
bool make_directory(const std::string& dir);
// @brief Gets the path of the system temporary directory
// @return the path to the system temporary directory
std::string get_temp_directory_path();
// @brief Removes a file from the filesystem
// @param file The path to the file to be removed
void remove_file(const std::string& file);
// @brief Reads the contents of a file
// @param path The path of the file to read
// @return vector<char> of the file's contents
std::vector<char> read_file_contents(const std::string& path);
// @brief Reads the contents of a file
// @param path The path of the file to read
// @return string of the file's contents
std::string read_file_to_string(const std::string& path);
// @brief Iterate through files and optionally directories. Symbolic links are skipped.
// @param path The path to iterate over
// @param func A callback function called with each file or directory encountered
// @param recurse Optional parameter to enable recursing through path
void iterate_files(const std::string& path,
std::function<void(const std::string& file, bool is_dir)> func,
bool recurse = false);
};
// @brief Create a temporary file
// @param extension Optional extension for the temporary file
// @return Name of the temporary file
std::string tmp_filename(const std::string& extension = "");
// @brief Test for the existence of a path or file
// @param path The path to test
// @param true if the path exists, false otherwise
bool exists(const std::string& path);
}
}
......@@ -17,6 +17,7 @@
#include <dlfcn.h>
#include <sstream>
#include "ngraph/file_util.hpp"
#include "ngraph/runtime/backend.hpp"
#include "ngraph/runtime/cpu/cpu_tensor_view.hpp"
#include "ngraph/util.hpp"
......@@ -42,6 +43,26 @@ runtime::Backend::~Backend()
{
}
// This doodad finds the full path of the containing shared library
static string find_my_file()
{
Dl_info dl_info;
dladdr(reinterpret_cast<void*>(find_my_file), &dl_info);
return dl_info.dli_fname;
}
// This will be uncommented when we add support for listing all known backends
// static bool is_backend(const string& path)
// {
// bool rc = false;
// string name = file_util::get_file_name(path);
// if (name.find("_backend.") != string::npos)
// {
// NGRAPH_INFO << name;
// }
// return rc;
// }
void* runtime::Backend::open_shared_library(string type)
{
string ext = SHARED_LIB_EXT;
......@@ -55,8 +76,11 @@ void* runtime::Backend::open_shared_library(string type)
{
type = type.substr(0, colon);
}
string name = "lib" + to_lower(type) + "_backend" + ext;
handle = dlopen(name.c_str(), RTLD_NOW | RTLD_GLOBAL);
string lib_name = "lib" + to_lower(type) + "_backend" + ext;
string my_directory = file_util::get_directory(find_my_file());
string full_path = file_util::path_join(my_directory, lib_name);
NGRAPH_INFO << full_path;
handle = dlopen(full_path.c_str(), RTLD_NOW | RTLD_GLOBAL);
if (handle)
{
function<void()> create_backend =
......@@ -68,14 +92,16 @@ void* runtime::Backend::open_shared_library(string type)
else
{
dlclose(handle);
throw runtime_error("Failed to find create_backend function in library '" + name + "'");
throw runtime_error("Failed to find create_backend function in library '" + lib_name +
"'");
}
s_open_backends.insert({name, handle});
s_open_backends.insert({lib_name, handle});
}
else
{
string err = dlerror();
throw runtime_error("Library open for Backend '" + name + "' failed with error:\n" + err);
throw runtime_error("Library open for Backend '" + lib_name + "' failed with error:\n" +
err);
}
return handle;
}
......
......@@ -52,7 +52,7 @@ shared_ptr<Node>
}
NodeVector new_outputs;
for (auto o : m_outputs)
for (auto o : m_output_nodes)
{
new_outputs.push_back(nm.get(o));
}
......@@ -65,7 +65,7 @@ ngraph::runtime::cpu::op::LoopKernel::LoopKernel(const NodeVector& node_list,
const NodeVector& args)
: RequiresTensorViewArgs("LoopKernel", {args})
, m_node_list(node_list)
, m_outputs(outputs)
, m_output_nodes(outputs)
{
auto ref = node_list.at(0);
for (auto n : node_list)
......
......@@ -39,10 +39,10 @@ namespace ngraph
copy_with_new_args(const NodeVector& new_args) const override;
const NodeVector& get_node_list() const { return m_node_list; }
const NodeVector& get_kernel_outputs() const { return m_outputs; }
const NodeVector& get_kernel_outputs() const { return m_output_nodes; }
private:
NodeVector m_node_list;
NodeVector m_outputs;
NodeVector m_output_nodes;
};
}
}
......
......@@ -90,8 +90,8 @@ TEST(file_util, path_join)
}
}
TEST(file_util, get_temp_directory)
TEST(file_util, get_temp_directory_path)
{
string tmp = file_util::get_temp_directory();
string tmp = file_util::get_temp_directory_path();
EXPECT_NE(0, tmp.size());
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment