added a C++ API

This commit is contained in:
Gregory Pakosz 2017-04-30 17:36:55 +02:00
parent 6d73e7898e
commit de7a01d322
7 changed files with 366 additions and 6 deletions

View File

@ -84,28 +84,48 @@ endif
.PHONY: build-executable .PHONY: build-executable
build: build-executable build: build-executable
build-executable: $(bindir)/executable $(bindir)/executable-cpp build-executable: $(bindir)/executable $(bindir)/executable-as-cxx $(bindir)/executable-as-cxx11 $(bindir)/executable-cxx $(bindir)/executable-cxx11
$(bindir)/executable: $(srcdir)/whereami.c $(srcdir)/whereami.h $(exampledir)/executable.c $(bindir)/executable: $(srcdir)/whereami.c $(srcdir)/whereami.h $(exampledir)/executable.c
mkdir -p $(@D) mkdir -p $(@D)
$(CC) -I $(srcdir) $(CPPFLAGS) $(CFLAGS) $(filter-out %.h,$^) $(LDFLAGS) -o $@ $(CC) -I $(srcdir) $(CPPFLAGS) $(CFLAGS) $(filter-out %.h,$^) $(LDFLAGS) -o $@
$(if $(postbuild),$(postbuild) $@) $(if $(postbuild),$(postbuild) $@)
$(bindir)/executable-cpp: $(srcdir)/whereami.c $(srcdir)/whereami.h $(exampledir)/executable.c $(bindir)/executable-as-cxx: $(srcdir)/whereami.c $(srcdir)/whereami.h $(exampledir)/executable.c
mkdir -p $(@D) mkdir -p $(@D)
$(CXX) -x c++ -I $(srcdir) $(CPPFLAGS) $(CXXFLAGS) $(filter-out %.h,$^) $(LDFLAGS) -o $@ $(CXX) -std=c++03 -x c++ -I $(srcdir) $(CPPFLAGS) $(CXXFLAGS) $(filter-out %.h,$^) $(LDFLAGS) -o $@
$(if $(postbuild),$(postbuild) $@)
$(bindir)/executable-as-cxx11: $(srcdir)/whereami.c $(srcdir)/whereami.h $(exampledir)/executable.c
mkdir -p $(@D)
$(CXX) -std=c++11 -x c++ -I $(srcdir) $(CPPFLAGS) $(CXXFLAGS) $(filter-out %.h,$^) $(LDFLAGS) -o $@
$(if $(postbuild),$(postbuild) $@)
$(bindir)/executable-cxx: $(srcdir)/whereami++.cpp $(srcdir)/whereami++.h $(exampledir)/executable.cpp
mkdir -p $(@D)
$(CXX) -std=c++03 -x c++ -I $(srcdir) $(CPPFLAGS) $(CXXFLAGS) $(filter-out %.h,$^) $(LDFLAGS) -o $@
$(if $(postbuild),$(postbuild) $@)
$(bindir)/executable-cxx11: $(srcdir)/whereami++.cpp $(srcdir)/whereami++.h $(exampledir)/executable.cpp
mkdir -p $(@D)
$(CXX) -std=c++11 -x c++ -I $(srcdir) $(CPPFLAGS) $(CXXFLAGS) $(filter-out %.h,$^) $(LDFLAGS) -o $@
$(if $(postbuild),$(postbuild) $@) $(if $(postbuild),$(postbuild) $@)
.PHONY: build-library .PHONY: build-library
build: build-library build: build-library
build-library: $(bindir)/library$(libsuffix) $(bindir)/library-cpp$(libsuffix) build-library: $(bindir)/library$(libsuffix) $(bindir)/library-as-cxx$(libsuffix) $(bindir)/library-cxx$(libsuffix)
$(bindir)/library$(libsuffix): $(srcdir)/whereami.c $(srcdir)/whereami.h $(exampledir)/library.c $(bindir)/library$(libsuffix): $(srcdir)/whereami.c $(srcdir)/whereami.h $(exampledir)/library.c
mkdir -p $(@D) mkdir -p $(@D)
$(CC) -I $(srcdir) $(CPPFLAGS) $(CFLAGS) $(filter-out %.h,$^) $(LDFLAGS) -shared -o $@ $(CC) -I $(srcdir) $(CPPFLAGS) $(CFLAGS) $(filter-out %.h,$^) $(LDFLAGS) -shared -o $@
$(if $(postbuild),$(postbuild) $@) $(if $(postbuild),$(postbuild) $@)
$(bindir)/library-cpp$(libsuffix): $(srcdir)/whereami.c $(srcdir)/whereami.h $(exampledir)/library.c $(bindir)/library-as-cxx$(libsuffix): $(srcdir)/whereami.c $(srcdir)/whereami.h $(exampledir)/library.c
mkdir -p $(@D)
$(CXX) -x c++ -I $(srcdir) $(CPPFLAGS) $(CXXFLAGS) $(filter-out %.h,$^) $(LDFLAGS) -shared -o $@
$(if $(postbuild),$(postbuild) $@)
$(bindir)/library-cxx$(libsuffix): $(srcdir)/whereami++.cpp $(srcdir)/whereami++.h $(exampledir)/library.cpp
mkdir -p $(@D) mkdir -p $(@D)
$(CXX) -x c++ -I $(srcdir) $(CPPFLAGS) $(CXXFLAGS) $(filter-out %.h,$^) $(LDFLAGS) -shared -o $@ $(CXX) -x c++ -I $(srcdir) $(CPPFLAGS) $(CXXFLAGS) $(filter-out %.h,$^) $(LDFLAGS) -shared -o $@
$(if $(postbuild),$(postbuild) $@) $(if $(postbuild),$(postbuild) $@)

101
example/executable.cpp Normal file
View File

@ -0,0 +1,101 @@
#include <iostream>
#include <whereami++.h>
#if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#if defined(_MSC_VER)
#pragma warning(push, 3)
#endif
#include <windows.h>
#define RTLD_LAZY 1
#define RTLD_NOW 2
#define RTLD_GLOBAL 4
#define RTLD_LOCAL 8
static void* dlopen(const char* fileName, int mode)
{
wchar_t buffer[MAX_PATH];
if (MultiByteToWideChar(CP_UTF8, 0, fileName, -1, buffer, sizeof(buffer) / sizeof(*buffer)))
{
wchar_t buffer_[MAX_PATH];
GetFullPathNameW(buffer, sizeof(buffer_) / sizeof(*buffer_), buffer_, NULL);
return (void*)LoadLibraryW(buffer_);
}
return NULL;
}
static int dlclose(void* handle)
{
return FreeLibrary((HMODULE)handle) ? 0 : -1;
}
static const char* dlerror(void)
{
DWORD error;
error = GetLastError();
if (error)
{
static char message[1024];
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), message, sizeof(message), NULL);
return message;
}
return "no error";
}
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
#else
#include <dlfcn.h>
#endif
int main(int argc, char** argv)
{
std::cout << "executable path: " << whereami::getExecutablePath() << std::endl;
whereami::whereami_path_t executablePath = whereami::getExecutablePath();
std::cout << " dirname: " << executablePath.dirname() << std::endl;
std::cout << " basename: " << executablePath.basename() << std::endl;
std::cout << "module path: " << whereami::getModulePath() << std::endl;
whereami::whereami_path_t modulePath = whereami::getModulePath();
std::cout << " dirname: " << modulePath.dirname() << std::endl;
std::cout << " basename: " << modulePath.basename() << std::endl;
for (int i = 1; i < argc; ++i)
{
std::string prefix = "--load-library=";
std::string arg = std::string(argv[i]);
if (arg.compare(0, prefix.length(), prefix) == 0)
{
std::string name = arg.substr(prefix.length());
void* handle;
std::cout << std::endl;
handle = dlopen(name.c_str(), RTLD_NOW);
if (!handle)
std::cout << "failed to load library: " << dlerror() << std::endl;
if (handle)
dlclose(handle);
}
}
return 0;
}

61
example/library.cpp Normal file
View File

@ -0,0 +1,61 @@
#include <iostream>
#include <whereami++.h>
#if defined(__GNUC__) && !defined(_WIN32)
__attribute__((constructor))
#endif
static void load()
{
std::cout << "library loaded" << std::endl;
std::cout << "executable path: " << whereami::getExecutablePath() << std::endl;
whereami::whereami_path_t executablePath = whereami::getExecutablePath();
std::cout << " dirname: " << executablePath.dirname() << std::endl;
std::cout << " basename: " << executablePath.basename() << std::endl;
std::cout << "module path: " << whereami::getModulePath() << std::endl;
whereami::whereami_path_t modulePath = whereami::getModulePath();
std::cout << " dirname: " << modulePath.dirname() << std::endl;
std::cout << " basename: " << modulePath.basename() << std::endl;
}
#if defined(__GNUC__) && !defined(_WIN32)
__attribute__((destructor))
#endif
static void unload()
{
std::cout << "library unloaded" << std::endl;
}
#if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#if defined(_MSC_VER)
#pragma warning(push, 3)
#endif
#include <windows.h>
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
load();
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
unload();
break;
}
return TRUE;
}
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
#endif

104
src/whereami++.cpp Normal file
View File

@ -0,0 +1,104 @@
// (‑●‑●)> released under the WTFPL v2 license, by Gregory Pakosz (@gpakosz)
// https://github.com/gpakosz/whereami
// in case you want to #include "whereami++.cpp" in a larger compilation unit
#if !defined(WHEREAMIPP_H)
#include <whereami++.h>
#endif
namespace whereami {
namespace {
#define WHEREAMI_H
#define WAI_FUNCSPEC
#define WAI_PREFIX(function) function
#include "whereami.c"
}
whereami_string_t whereami_path_t::dirname() const
{
return path.substr(0, dirname_length);
}
whereami_string_t whereami_path_t::basename() const
{
return path.substr(dirname_length + 1);
}
#if defined(WHEREAMI_CXX11)
whereami_path_t::operator whereami_string_t() &&
{
return std::move(path);
}
whereami_path_t::operator whereami_string_t() const &
{
return path;
}
#else
whereami_path_t::operator const whereami_string_t&() const
{
return path;
}
#endif
#if defined(WHEREAMI_CXX11)
whereami_path_t::whereami_path_t(whereami_string_t&& path, int dirname_length) noexcept
: path(std::move(path)), dirname_length(dirname_length)
{
}
#else
whereami_path_t::whereami_path_t(whereami_string_t& path, int dirname_length)
: path(path), dirname_length(dirname_length)
{
}
#endif
#if !defined(WHEREAMI_DISABLE_OSTREAM)
std::ostream& operator<<(std::ostream& os, const whereami_path_t& path)
{
return os << path.path;
}
#endif
WAI_FUNCSPEC
whereami_path_t getExecutablePath()
{
whereami_string_t path;
int dirname_length = -1;
int length = getExecutablePath(0, 0, 0);
if (length != -1)
{
path.resize(length);
getExecutablePath(&path[0], length, &dirname_length);
}
#if defined(WHEREAMI_CXX11)
return whereami_path_t(std::move(path), dirname_length);
#else
return whereami_path_t(path, dirname_length);
#endif
}
WAI_FUNCSPEC
whereami_path_t getModulePath()
{
whereami_string_t path;
int dirname_length = -1;
int length = getModulePath(0, 0, 0);
if (length != -1)
{
path.resize(length);
getModulePath(&path[0], length, &dirname_length);
}
#if defined(WHEREAMI_CXX11)
return whereami_path_t(std::move(path), dirname_length);
#else
return whereami_path_t(path, dirname_length);
#endif
}
} // namespace whereami

67
src/whereami++.h Normal file
View File

@ -0,0 +1,67 @@
// (‑●‑●)> released under the WTFPL v2 license, by Gregory Pakosz (@gpakosz)
// https://github.com/gpakosz/whereami
#ifndef WHEREAMIPP_H
#define WHEREAMIPP_H
#if !defined(WHEREAMI_STRING_T)
#include <string>
typedef std::string whereami_string_t;
#else
typedef WHEREAMI_STRING_T whereami_string_t;
#endif
#if !defined(WHEREAMI_DISABLE_OSTREAM)
#include <ostream>
#endif
#if (defined (__cplusplus) && (__cplusplus > 199711L)) || (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 150020706))
#define WHEREAMI_CXX11
#endif
namespace whereami {
class whereami_path_t
{
public:
#if defined(WHEREAMI_CXX11)
operator whereami_string_t() &&;
operator whereami_string_t() const &;
#else
operator const whereami_string_t&() const;
#endif
whereami_string_t dirname() const;
whereami_string_t basename() const;
private:
whereami_path_t();
#if defined(WHEREAMI_CXX11)
whereami_path_t(whereami_string_t&& path, int dirname_length) noexcept;
#else
whereami_path_t(whereami_string_t& path, int dirname_length);
#endif
friend whereami_path_t getExecutablePath();
friend whereami_path_t getModulePath();
#if !defined(WHEREAMI_DISABLE_OSTREAM)
friend std::ostream& operator<<(std::ostream& os, const whereami_path_t& path);
#endif
whereami_string_t path;
int dirname_length;
};
/**
* Returns the path to the current executable.
*/
whereami_path_t getExecutablePath();
/**
* Returns the path to the current module.
*/
whereami_path_t getModulePath();
} // namespace whereami
#endif // #ifndef WHEREAMIPP_H

View File

@ -10,6 +10,13 @@
extern "C" { extern "C" {
#endif #endif
#ifndef WAI_FUNCSPEC
#define WAI_FUNCSPEC
#endif
#ifndef WAI_PREFIX
#define WAI_PREFIX(function) wai_##function
#endif
#if !defined(WAI_MALLOC) || !defined(WAI_FREE) || !defined(WAI_REALLOC) #if !defined(WAI_MALLOC) || !defined(WAI_FREE) || !defined(WAI_REALLOC)
#include <stdlib.h> #include <stdlib.h>
#endif #endif

View File

@ -38,7 +38,7 @@ WAI_FUNCSPEC
int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length); int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length);
/** /**
* Returns the path to the current module * Returns the path to the current module.
* *
* Usage: * Usage:
* - first call `int length = wai_getModulePath(NULL, 0, NULL);` to retrieve * - first call `int length = wai_getModulePath(NULL, 0, NULL);` to retrieve