Skip to content

Commit

Permalink
added a C++ API
Browse files Browse the repository at this point in the history
  • Loading branch information
gpakosz committed May 1, 2017
1 parent 523c28a commit 7896790
Show file tree
Hide file tree
Showing 7 changed files with 366 additions and 6 deletions.
30 changes: 25 additions & 5 deletions _gnu-make/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -84,28 +84,48 @@ endif

.PHONY: 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
mkdir -p $(@D)
$(CC) -I $(srcdir) $(CPPFLAGS) $(CFLAGS) $(filter-out %.h,$^) $(LDFLAGS) -o $@
$(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)
$(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) $@)

.PHONY: 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
mkdir -p $(@D)
$(CC) -I $(srcdir) $(CPPFLAGS) $(CFLAGS) $(filter-out %.h,$^) $(LDFLAGS) -shared -o $@
$(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)
$(CXX) -x c++ -I $(srcdir) $(CPPFLAGS) $(CXXFLAGS) $(filter-out %.h,$^) $(LDFLAGS) -shared -o $@
$(if $(postbuild),$(postbuild) $@)
Expand Down
101 changes: 101 additions & 0 deletions example/executable.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 61 additions & 0 deletions example/library.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 104 additions & 0 deletions src/whereami++.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 67 additions & 0 deletions src/whereami++.h
Original file line number Diff line number Diff line change
@@ -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

Loading

0 comments on commit 7896790

Please sign in to comment.