aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2019-08-04 23:37:58 +0200
committerDavid Robillard <d@drobilla.net>2020-03-11 20:32:58 +0100
commit315b1a784d270c9f3ca0d430c3c1802a3ebfd918 (patch)
treed5757ecf31b3287a66e2ad53cca07c1c4f6c5f15
parent5c02f37c8d1dd74f3b72f1fb0b2a77f4d1dc2da9 (diff)
downloadpugl-c++.tar.gz
pugl-c++.tar.bz2
pugl-c++.zip
WIP: Update C++ bindingsc++
-rw-r--r--.clang-format2
-rw-r--r--.clang-tidy15
-rw-r--r--examples/pugl_cxx_demo.cpp119
-rw-r--r--pugl/pugl.hpp437
-rw-r--r--wscript31
5 files changed, 553 insertions, 51 deletions
diff --git a/.clang-format b/.clang-format
index b788676..1c3e537 100644
--- a/.clang-format
+++ b/.clang-format
@@ -104,7 +104,7 @@ SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
-SpaceBeforeCpp11BracedList: true
+SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
diff --git a/.clang-tidy b/.clang-tidy
index 0f46134..d714003 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -1,14 +1,27 @@
Checks: >
*,
+ -*avoid-c-arrays,
-*magic-numbers,
+ -*non-private-member-variables-in-classes,
-*uppercase-literal-suffix,
-android-cloexec-fopen,
-bugprone-suspicious-string-compare,
-clang-analyzer-alpha.*,
+ -cppcoreguidelines-macro-usage,
+ -cppcoreguidelines-pro-bounds-array-to-pointer-decay,
+ -cppcoreguidelines-pro-bounds-pointer-arithmetic,
+ -cppcoreguidelines-pro-type-static-cast-downcast,
+ -cppcoreguidelines-pro-type-vararg,
+ -google-runtime-references,
-hicpp-multiway-paths-covered,
+ -hicpp-no-array-decay,
-hicpp-signed-bitwise,
+ -hicpp-vararg,
-llvm-header-guard,
- -readability-else-after-return
+ -modernize-use-trailing-return-type,
+ -readability-else-after-return,
+ -readability-implicit-bool-conversion,
+ -readability-named-parameter,
WarningsAsErrors: ''
HeaderFilterRegex: 'pugl/.*|test/.*'
FormatStyle: file
diff --git a/examples/pugl_cxx_demo.cpp b/examples/pugl_cxx_demo.cpp
new file mode 100644
index 0000000..4043486
--- /dev/null
+++ b/examples/pugl_cxx_demo.cpp
@@ -0,0 +1,119 @@
+/*
+ Copyright 2012-2019 David Robillard <http://drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/**
+ @file pugl_test.c A simple Pugl test that creates a top-level window.
+*/
+
+#define GL_SILENCE_DEPRECATION 1
+
+#include "cube_view.h"
+#include "demo_utils.h"
+#include "test/test_utils.h"
+
+#include "pugl/gl.h"
+#include "pugl/pugl.hpp"
+#include "pugl/pugl_gl.h"
+
+#include <cmath>
+#include <cstdint>
+#include <type_traits>
+#include <utility>
+
+struct CubeData {
+ double xAngle{0.0};
+ double yAngle{0.0};
+ double lastDrawTime{0.0};
+ unsigned framesDrawn{0};
+ bool quit{false};
+};
+
+using CubeView = pugl::View<CubeData>;
+
+static pugl::Status
+onConfigure(CubeView&, const pugl::ConfigureEvent& event)
+{
+ reshapeCube(event.width, event.height);
+
+ return pugl::Status::success;
+}
+
+static pugl::Status
+onExpose(CubeView& view, const pugl::ExposeEvent&)
+{
+ const pugl::World& world = view.getWorld();
+ CubeData& data = view.getData();
+ const double thisTime = world.getTime();
+ const double dTime = thisTime - data.lastDrawTime;
+ const double dAngle = dTime * 100.0;
+
+ data.xAngle = fmod(data.xAngle + dAngle, 360.0);
+ data.yAngle = fmod(data.yAngle + dAngle, 360.0);
+ displayCube(view.cobj(), 8.0, data.xAngle, data.yAngle, false);
+
+ data.lastDrawTime = thisTime;
+ ++data.framesDrawn;
+
+ return pugl::Status::success;
+}
+
+static pugl::Status
+onKeyPress(CubeView& view, const pugl::KeyPressEvent& event)
+{
+ if (event.key == PUGL_KEY_ESCAPE || event.key == 'q') {
+ view.getData().quit = true;
+ }
+
+ return pugl::Status::success;
+}
+
+int
+main(int argc, char** argv)
+{
+ const PuglTestOptions opts = puglParseTestOptions(&argc, &argv);
+
+ pugl::World world;
+ CubeView view{world};
+ PuglFpsPrinter fpsPrinter{};
+
+ world.setClassName("Pugl C++ Test");
+
+ view.setFrame({0, 0, 512, 512});
+ view.setMinSize(64, 64);
+ view.setAspectRatio(1, 1, 16, 9);
+ view.setBackend(puglGlBackend());
+ view.setHint(pugl::ViewHint::resizable, opts.resizable);
+ view.setHint(pugl::ViewHint::samples, opts.samples);
+ view.setHint(pugl::ViewHint::doubleBuffer, opts.doubleBuffer);
+ view.setHint(pugl::ViewHint::swapInterval, opts.doubleBuffer);
+ view.setHint(pugl::ViewHint::ignoreKeyRepeat, opts.ignoreKeyRepeat);
+
+ view.setEventFunc(onConfigure);
+ view.setEventFunc(onExpose);
+ view.setEventFunc(onKeyPress);
+
+ view.createWindow("Pugl C++ Test");
+ view.showWindow();
+
+ while (!view.getData().quit) {
+ view.postRedisplay();
+ world.dispatchEvents();
+
+ puglPrintFps(world.cobj(), &fpsPrinter, &view.getData().framesDrawn);
+ }
+
+ return 0;
+}
diff --git a/pugl/pugl.hpp b/pugl/pugl.hpp
index 73cfe2a..18451ee 100644
--- a/pugl/pugl.hpp
+++ b/pugl/pugl.hpp
@@ -22,6 +22,13 @@
#define PUGL_PUGL_HPP
#include "pugl/pugl.h"
+#include "pugl/pugl_gl.h" // FIXME
+
+#include <chrono>
+#include <functional>
+#include <ratio>
+#include <stdexcept>
+#include <utility>
/**
@defgroup puglxx C++
@@ -37,84 +44,430 @@
*/
namespace pugl {
-/**
- A drawable region that receives events.
+enum class Status {
+ success = PUGL_SUCCESS,
+ failure = PUGL_FAILURE,
+ unknownError = PUGL_UNKNOWN_ERROR,
+ badBackend = PUGL_BAD_BACKEND,
+ backendFailed = PUGL_BACKEND_FAILED,
+ registrationFailed = PUGL_REGISTRATION_FAILED,
+ createWindowFailed = PUGL_CREATE_WINDOW_FAILED,
+ setFormatFailed = PUGL_SET_FORMAT_FAILED,
+ createContextFailed = PUGL_CREATE_CONTEXT_FAILED,
+ unsupportedType = PUGL_UNSUPPORTED_TYPE,
+};
- This is a thin wrapper for a PuglView that contains only a pointer.
+enum class ViewHint {
+ useCompatProfile, ///< Use compatible (not core) OpenGL profile
+ useDebugContext, ///< True to use a debug OpenGL context
+ contextVersionMajor, ///< OpenGL context major version
+ contextVersionMinor, ///< OpenGL context minor version
+ redBits, ///< Number of bits for red channel
+ greenBits, ///< Number of bits for green channel
+ blueBits, ///< Number of bits for blue channel
+ alphaBits, ///< Number of bits for alpha channel
+ depthBits, ///< Number of bits for depth buffer
+ stencilBits, ///< Number of bits for stencil buffer
+ samples, ///< Number of samples per pixel (AA)
+ doubleBuffer, ///< True if double buffering should be used
+ swapInterval, ///< Number of frames between buffer swaps
+ resizable, ///< True if window should be resizable
+ ignoreKeyRepeat, ///< True if key repeat events are ignored
+};
- @ingroup puglxx
-*/
-class View {
+using Rect = PuglRect;
+using NativeWindow = PuglNativeWindow;
+using GlFunc = PuglGlFunc;
+using Event = PuglEvent;
+
+template<PuglEventType t, class Base>
+struct TypedEvent : public Base {
+ static constexpr const PuglEventType type = t;
+};
+
+/* Strong types for every event type. */
+
+using ButtonPressEvent = TypedEvent<PUGL_BUTTON_PRESS, PuglEventButton>;
+using ButtonReleaseEvent = TypedEvent<PUGL_BUTTON_RELEASE, PuglEventButton>;
+using CreateEvent = TypedEvent<PUGL_CREATE, PuglEventAny>;
+using DestroyEvent = TypedEvent<PUGL_DESTROY, PuglEventAny>;
+using MapEvent = TypedEvent<PUGL_MAP, PuglEventAny>;
+using UnmapEvent = TypedEvent<PUGL_UNMAP, PuglEventAny>;
+using ConfigureEvent = TypedEvent<PUGL_CONFIGURE, PuglEventConfigure>;
+using ExposeEvent = TypedEvent<PUGL_EXPOSE, PuglEventExpose>;
+using CloseEvent = TypedEvent<PUGL_CLOSE, PuglEventAny>;
+using KeyPressEvent = TypedEvent<PUGL_KEY_PRESS, PuglEventKey>;
+using KeyReleaseEvent = TypedEvent<PUGL_KEY_RELEASE, PuglEventKey>;
+using TextEvent = TypedEvent<PUGL_TEXT, PuglEventText>;
+using EnterEvent = TypedEvent<PUGL_ENTER_NOTIFY, PuglEventCrossing>;
+using LeaveEvent = TypedEvent<PUGL_LEAVE_NOTIFY, PuglEventCrossing>;
+using MotionEvent = TypedEvent<PUGL_MOTION_NOTIFY, PuglEventMotion>;
+using ScrollEvent = TypedEvent<PUGL_SCROLL, PuglEventScroll>;
+using FocusInEvent = TypedEvent<PUGL_FOCUS_IN, PuglEventFocus>;
+using FocusOutEvent = TypedEvent<PUGL_FOCUS_OUT, PuglEventFocus>;
+using ClientEvent = TypedEvent<PUGL_CLIENT, PuglEventClient>;
+
+static inline const char*
+strerror(pugl::Status status)
+{
+ return puglStrerror(static_cast<PuglStatus>(status));
+}
+
+static inline GlFunc
+getProcAddress(const char* name)
+{
+ return puglGetProcAddress(name);
+}
+
+class World;
+
+class Clock
+{
+public:
+ using rep = double;
+ using period = std::ratio<1>;
+ using duration = std::chrono::duration<double>;
+ using time_point = std::chrono::time_point<Clock>;
+
+ static constexpr bool is_steady = true;
+
+ explicit Clock(World& world)
+ : _world{world}
+ {}
+
+ time_point now() const;
+
+private:
+ const pugl::World& _world;
+};
+
+class World
+{
+public:
+ World()
+ : _clock(*this)
+ , _world(puglNewWorld())
+ {
+ if (!_world) {
+ throw std::runtime_error("Failed to create pugl::World");
+ }
+ }
+
+ ~World() { puglFreeWorld(_world); }
+
+ World(const World&) = delete;
+ World& operator=(const World&) = delete;
+ World(World&&) = delete;
+ World&& operator=(World&&) = delete;
+
+ Status setClassName(const char* const name)
+ {
+ return static_cast<Status>(puglSetClassName(_world, name));
+ }
+
+ double getTime() const { return puglGetTime(_world); }
+
+ Status pollEvents(const double timeout)
+ {
+ return static_cast<Status>(puglPollEvents(_world, timeout));
+ }
+
+ Status dispatchEvents()
+ {
+ return static_cast<Status>(puglDispatchEvents(_world));
+ }
+
+ const PuglWorld* cobj() const { return _world; }
+ PuglWorld* cobj() { return _world; }
+
+ const Clock& clock() { return _clock; }
+
+private:
+ Clock _clock;
+ PuglWorld* const _world;
+};
+
+inline Clock::time_point
+Clock::now() const
+{
+ return time_point{duration{_world.getTime()}};
+}
+
+class ViewBase
+{
public:
- View(int* pargc, char** argv)
- : _view(puglInit(pargc, argv))
+ explicit ViewBase(World& world)
+ : _world(world)
+ , _view(puglNewView(world.cobj()))
{
+ if (!_view) {
+ throw std::runtime_error("Failed to create pugl::View");
+ }
+
puglSetHandle(_view, this);
- puglSetEventFunc(_view, _onEvent);
}
- virtual ~View() { puglDestroy(_view); }
+ ~ViewBase() { puglFreeView(_view); }
+
+ ViewBase(const ViewBase&) = delete;
+ ViewBase(ViewBase&&) = delete;
+ ViewBase& operator=(const ViewBase&) = delete;
+ ViewBase&& operator=(ViewBase&&) = delete;
+
+ Status setHint(ViewHint hint, int value)
+ {
+ return static_cast<Status>(
+ puglSetViewHint(_view, static_cast<PuglViewHint>(hint), value));
+ }
+
+ bool getVisible() const { return puglGetVisible(_view); }
+
+ Status postRedisplay()
+ {
+ return static_cast<Status>(puglPostRedisplay(_view));
+ }
+
+ const pugl::World& getWorld() const { return _world; }
+ pugl::World& getWorld() { return _world; }
+
+ Rect getFrame() const { return puglGetFrame(_view); }
- virtual void initWindowParent(PuglNativeWindow parent) {
- puglInitWindowParent(_view, parent);
+ Status setFrame(Rect frame)
+ {
+ return static_cast<Status>(puglSetFrame(_view, frame));
}
- virtual void initWindowSize(int width, int height) {
- puglInitWindowSize(_view, width, height);
+ Status setMinSize(int width, int height)
+ {
+ return static_cast<Status>(puglSetMinSize(_view, width, height));
}
- virtual void initWindowMinSize(int width, int height) {
- puglInitWindowMinSize(_view, width, height);
+ Status setAspectRatio(int minX, int minY, int maxX, int maxY)
+ {
+ return static_cast<Status>(
+ puglSetAspectRatio(_view, minX, minY, maxX, maxY));
}
- virtual void initWindowAspectRatio(int min_x, int min_y, int max_x, int max_y) {
- puglInitWindowAspectRatio(_view, min_x, min_y, max_x, max_y);
+ Status setWindowTitle(const char* title)
+ {
+ return static_cast<Status>(puglSetWindowTitle(_view, title));
}
- virtual void initResizable(bool resizable) {
- puglInitResizable(_view, resizable);
+ Status setParentWindow(NativeWindow parent)
+ {
+ return static_cast<Status>(puglSetParentWindow(_view, parent));
}
- virtual void initTransientFor(uintptr_t parent) {
- puglInitTransientFor(_view, parent);
+ Status setTransientFor(NativeWindow parent)
+ {
+ return static_cast<Status>(puglSetTransientFor(_view, parent));
}
- virtual void initBackend(const PuglBackend* backend) {
- puglInitBackend(_view, backend);
+ Status createWindow(const char* title)
+ {
+ return static_cast<Status>(puglCreateWindow(_view, title));
}
- virtual void createWindow(const char* title) {
- puglCreateWindow(_view, title);
+ Status showWindow() { return static_cast<Status>(puglShowWindow(_view)); }
+
+ Status hideWindow() { return static_cast<Status>(puglHideWindow(_view)); }
+
+ NativeWindow getNativeWindow() { return puglGetNativeWindow(_view); }
+
+ Status setBackend(const PuglBackend* backend)
+ {
+ return static_cast<Status>(puglSetBackend(_view, backend));
}
- virtual void showWindow() { puglShowWindow(_view); }
- virtual void hideWindow() { puglHideWindow(_view); }
- virtual PuglNativeWindow getNativeWindow() { return puglGetNativeWindow(_view); }
+ void* getContext() { return puglGetContext(_view); }
- virtual void onEvent(const PuglEvent* event) = 0;
+ bool hasFocus() const { return puglHasFocus(_view); }
- virtual void* getContext() { return puglGetContext(_view); }
- virtual void ignoreKeyRepeat(bool ignore) { puglIgnoreKeyRepeat(_view, ignore); }
- virtual void grabFocus() { puglGrabFocus(_view); }
- virtual void requestAttention() { puglRequestAttention(_view); }
- virtual PuglStatus waitForEvent() { return puglWaitForEvent(_view); }
- virtual PuglStatus processEvents() { return puglProcessEvents(_view); }
- virtual void postRedisplay() { puglPostRedisplay(_view); }
+ Status grabFocus() { return static_cast<Status>(puglGrabFocus(_view)); }
+
+ Status requestAttention()
+ {
+ return static_cast<Status>(puglRequestAttention(_view));
+ }
PuglView* cobj() { return _view; }
+protected:
+ World& _world;
+ PuglView* _view;
+};
+
+/**
+ A drawable region that receives events.
+
+ This is a thin wrapper for a PuglView that contains only a pointer.
+
+ @ingroup puglxx
+*/
+template<typename Data>
+class View : public ViewBase
+{
+public:
+ template<class E>
+ using TypedEventFunc = std::function<pugl::Status(View&, const E&)>;
+
+ using NothingEvent = TypedEvent<PUGL_NOTHING, PuglEvent>;
+
+ /**
+ A tuple of event handlers, one for each event type.
+
+ Note that the indices here must correspond to PuglEventType.
+ */
+ using EventFuncs = std::tuple<TypedEventFunc<NothingEvent>,
+ TypedEventFunc<ButtonPressEvent>,
+ TypedEventFunc<ButtonReleaseEvent>,
+ TypedEventFunc<CreateEvent>,
+ TypedEventFunc<DestroyEvent>,
+ TypedEventFunc<MapEvent>,
+ TypedEventFunc<UnmapEvent>,
+ TypedEventFunc<ConfigureEvent>,
+ TypedEventFunc<ExposeEvent>,
+ TypedEventFunc<CloseEvent>,
+ TypedEventFunc<KeyPressEvent>,
+ TypedEventFunc<KeyReleaseEvent>,
+ TypedEventFunc<TextEvent>,
+ TypedEventFunc<EnterEvent>,
+ TypedEventFunc<LeaveEvent>,
+ TypedEventFunc<MotionEvent>,
+ TypedEventFunc<ScrollEvent>,
+ TypedEventFunc<FocusInEvent>,
+ TypedEventFunc<FocusOutEvent>,
+ TypedEventFunc<ClientEvent>>;
+
+ using EventFunc = std::function<pugl::Status(View&, const PuglEvent&)>;
+
+ explicit View(World& world)
+ : ViewBase{world}
+ , _data{}
+ {
+ puglSetEventFunc(_view, _onEvent);
+ }
+
+ View(World& world, Data data)
+ : ViewBase{world}
+ , _data{data}
+ {
+ puglSetEventFunc(_view, _onEvent);
+ }
+
+ template<class HandledEvent>
+ Status setEventFunc(
+ std::function<pugl::Status(View&, const HandledEvent&)> handler)
+ {
+ std::get<HandledEvent::type>(_eventFuncs) = handler;
+
+ return Status::success;
+ }
+
+ template<class HandledEvent>
+ Status setEventFunc(pugl::Status (*handler)(View&, const HandledEvent&))
+ {
+ std::get<HandledEvent::type>(_eventFuncs) = handler;
+
+ return Status::success;
+ }
+
+ const Data& getData() const { return _data; }
+ Data& getData() { return _data; }
+
private:
- static void _onEvent(PuglView* view, const PuglEvent* event) {
- ((View*)puglGetHandle(view))->onEvent(event);
+ static PuglStatus _onEvent(PuglView* view, const PuglEvent* event) noexcept
+ {
+ View* self = static_cast<View*>(puglGetHandle(view));
+
+ return static_cast<PuglStatus>(self->dispatchEvent(*event));
}
- PuglView* _view;
+ Status dispatchEvent(const PuglEvent& event)
+ {
+ switch (event.type) {
+ case PUGL_NOTHING:
+ return Status::success;
+ case PUGL_BUTTON_PRESS:
+ return dispatchTypedEvent(
+ static_cast<const ButtonPressEvent&>(event.button));
+ case PUGL_BUTTON_RELEASE:
+ return dispatchTypedEvent(
+ static_cast<const ButtonReleaseEvent&>(event.button));
+ case PUGL_CREATE:
+ return dispatchTypedEvent(
+ static_cast<const CreateEvent&>(event.any));
+ case PUGL_DESTROY:
+ return dispatchTypedEvent(
+ static_cast<const DestroyEvent&>(event.any));
+ case PUGL_MAP:
+ return dispatchTypedEvent(static_cast<const MapEvent&>(event.any));
+ case PUGL_UNMAP:
+ return dispatchTypedEvent(
+ static_cast<const UnmapEvent&>(event.any));
+ case PUGL_CONFIGURE:
+ return dispatchTypedEvent(
+ static_cast<const ConfigureEvent&>(event.configure));
+ case PUGL_EXPOSE:
+ return dispatchTypedEvent(
+ static_cast<const ExposeEvent&>(event.expose));
+ case PUGL_CLOSE:
+ return dispatchTypedEvent(
+ static_cast<const CloseEvent&>(event.any));
+ case PUGL_KEY_PRESS:
+ return dispatchTypedEvent(
+ static_cast<const KeyPressEvent&>(event.key));
+ case PUGL_KEY_RELEASE:
+ return dispatchTypedEvent(
+ static_cast<const KeyReleaseEvent&>(event.key));
+ case PUGL_TEXT:
+ return dispatchTypedEvent(
+ static_cast<const TextEvent&>(event.text));
+ case PUGL_ENTER_NOTIFY:
+ return dispatchTypedEvent(
+ static_cast<const EnterEvent&>(event.crossing));
+ case PUGL_LEAVE_NOTIFY:
+ return dispatchTypedEvent(
+ static_cast<const LeaveEvent&>(event.crossing));
+ case PUGL_MOTION_NOTIFY:
+ return dispatchTypedEvent(
+ static_cast<const MotionEvent&>(event.motion));
+ case PUGL_SCROLL:
+ return dispatchTypedEvent(
+ static_cast<const ScrollEvent&>(event.scroll));
+ case PUGL_FOCUS_IN:
+ return dispatchTypedEvent(
+ static_cast<const FocusInEvent&>(event.focus));
+ case PUGL_FOCUS_OUT:
+ return dispatchTypedEvent(
+ static_cast<const FocusOutEvent&>(event.focus));
+ case PUGL_CLIENT:
+ return dispatchTypedEvent(
+ static_cast<const ClientEvent&>(event.client));
+ }
+
+ return Status::failure;
+ }
+
+ template<class E>
+ Status dispatchTypedEvent(const E& event)
+ {
+ auto& handler = std::get<E::type>(_eventFuncs);
+ if (handler) {
+ return handler(*this, event);
+ }
+
+ return Status::success;
+ }
+
+ Data _data;
+ EventFuncs _eventFuncs;
};
-} // namespace pugl
+} // namespace pugl
/**
@}
*/
-#endif /* PUGL_PUGL_HPP */
+#endif /* PUGL_PUGL_HPP */
diff --git a/wscript b/wscript
index 510b260..7445e01 100644
--- a/wscript
+++ b/wscript
@@ -22,6 +22,7 @@ out = 'build' # Build directory
def options(ctx):
ctx.load('compiler_c')
+ ctx.load('compiler_cxx')
opts = ctx.configuration_options()
opts.add_option('--target', default=None, dest='target',
@@ -43,24 +44,34 @@ def options(ctx):
def configure(conf):
conf.load('compiler_c', cache=True)
+ try:
+ conf.load('compiler_cxx', cache=True)
+ except Exception:
+ pass
+
conf.load('autowaf', cache=True)
autowaf.set_c_lang(conf, 'c99')
+ if 'COMPILER_CXX' in conf.env:
+ autowaf.set_cxx_lang(conf, 'c++11')
conf.env.ALL_HEADERS = Options.options.all_headers
conf.env.TARGET_PLATFORM = Options.options.target or sys.platform
platform = conf.env.TARGET_PLATFORM
+ def append_cflags(flags):
+ conf.env.append_value('CFLAGS', flags)
+ conf.env.append_value('CXXFLAGS', flags)
+
if platform == 'darwin':
- conf.env.append_unique('CFLAGS', ['-Wno-deprecated-declarations'])
+ append_cflags(['-Wno-deprecated-declarations'])
if conf.env.MSVC_COMPILER:
- conf.env.append_unique('CFLAGS', ['/wd4191'])
+ append_cflags(['/wd4191'])
else:
- conf.env.append_value('LINKFLAGS', ['-fvisibility=hidden'])
- conf.env.append_value('CFLAGS', ['-fvisibility=hidden'])
+ conf.env.append_unique('LINKFLAGS', ['-fvisibility=hidden'])
+ append_cflags(['-fvisibility=hidden'])
if Options.options.strict:
- conf.env.append_value('CFLAGS', ['-Wunused-parameter',
- '-Wno-pedantic'])
+ append_cflags(['-Wunused-parameter', '-Wno-pedantic'])
if Options.options.ultra_strict and 'clang' in conf.env.CC:
for var in ['CFLAGS', 'CXXFLAGS']:
@@ -289,6 +300,8 @@ def build(bld):
source=['pugl/detail/x11_cairo.c'])
def build_example(prog, source, platform, backend, **kwargs):
+ lang = 'cxx' if source[0].endswith('.cpp') else 'c'
+
use = ['pugl_%s_static' % platform,
'pugl_%s_%s_static' % (platform, backend)]
@@ -308,7 +321,7 @@ def build(bld):
deps.get(platform, {}).get(k, []) +
deps.get(backend_lib, {}).get(k, []))})
- bld(features = 'c cprogram',
+ bld(features = '%s %sprogram' % (lang, lang),
source = source,
target = target,
use = use,
@@ -349,6 +362,10 @@ def build(bld):
'pugl_%s_stub_static' % platform],
uselib = deps[platform]['uselib'] + ['CAIRO'])
+ if bld.env.CXX and bld.env.HAVE_GL:
+ build_example('pugl_cxx_demo', ['examples/pugl_cxx_demo.cpp'],
+ platform, 'gl', uselib=['GL', 'M'])
+
if bld.env.DOCS:
autowaf.build_dox(bld, 'PUGL', PUGL_VERSION, top, out)