From b0950785e72d9d59c6fd816c01d203ecb083c663 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Wed, 20 Dec 2017 20:03:16 +0100 Subject: Add the sdl_mouse module implementing half of sdl_mouse.h The latter half will be part of sdl_cursor. This depends on some changes to nif_helper. The sdl_gl part of the code is probably slithly broken now, the dependency on the window is gone. This will be resolved later on. --- Makefile | 4 + c_src/esdl2.c | 4 + c_src/esdl2.h | 37 +++ c_src/esdl2_renderers.c | 104 ++++++++ c_src/esdl2_windows.c | 97 ++++++++ c_src/sdl_gl.c | 5 +- c_src/sdl_mouse.c | 224 +++++++++++++++++ c_src/sdl_renderer.c | 12 +- c_src/sdl_window.c | 14 +- ebin/esdl2.app | 2 +- erlang.mk | 509 ++++++++++++++++++++++++++------------- examples/hello_sdl/hello_sdl.erl | 2 +- src/esdl2.erl | 40 +++ src/sdl_mouse.erl | 72 ++++++ 14 files changed, 953 insertions(+), 173 deletions(-) create mode 100644 c_src/esdl2_renderers.c create mode 100644 c_src/esdl2_windows.c create mode 100644 c_src/sdl_mouse.c create mode 100644 src/sdl_mouse.erl diff --git a/Makefile b/Makefile index 89fca3b..4fd1595 100644 --- a/Makefile +++ b/Makefile @@ -39,6 +39,10 @@ scan-build: make clean scan-build make +hello_sdl:: all + erlc -o examples/hello_sdl examples/hello_sdl/*.erl + cd examples/hello_sdl && ./start.sh + bullet_engine:: all erlc -o examples/bullet_engine examples/bullet_engine/*.erl cd examples/bullet_engine && ./start.sh diff --git a/c_src/esdl2.c b/c_src/esdl2.c index 1790dd7..82bea2d 100644 --- a/c_src/esdl2.c +++ b/c_src/esdl2.c @@ -27,6 +27,8 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) *priv_data = nif_create_main_thread("esdl2"); + esdl2_windows_init(); + loads++; return 0; @@ -46,6 +48,8 @@ static void unload(ErlNifEnv* env, void* priv_data) if (loads == 1) nif_destroy_main_thread(priv_data); + esdl2_windows_free(); + loads--; } diff --git a/c_src/esdl2.h b/c_src/esdl2.h index 10508ff..ca9a424 100644 --- a/c_src/esdl2.h +++ b/c_src/esdl2.h @@ -23,6 +23,7 @@ A(accelerated) \ A(add) \ A(allow_high_dpi) \ + A(arrow) \ A(audio) \ A(blend) \ A(borderless) \ @@ -34,6 +35,7 @@ A(charging) \ A(clicks) \ A(close) \ + A(crosshair) \ A(data) \ A(enter) \ A(error) \ @@ -42,6 +44,7 @@ A(everything) \ A(exposed) \ A(false) \ + A(flipped) \ A(focus_gained) \ A(focus_lost) \ A(foreign) \ @@ -49,9 +52,11 @@ A(fullscreen_desktop) \ A(game_controller) \ A(h) \ + A(hand) \ A(haptic) \ A(hidden) \ A(horizontal) \ + A(ibeam) \ A(input_focus) \ A(input_grabbed) \ A(joystick) \ @@ -69,14 +74,17 @@ A(minimized) \ A(mod) \ A(mode) \ + A(mouse_capture) \ A(mouse_down) \ A(mouse_focus) \ A(mouse_motion) \ A(mouse_up) \ A(mouse_wheel) \ A(moved) \ + A(no) \ A(no_battery) \ A(none) \ + A(normal) \ A(num) \ A(on_battery) \ A(opengl) \ @@ -93,7 +101,12 @@ A(right_shift) \ A(scancode) \ A(shown) \ + A(size_all) \ A(size_changed) \ + A(size_nesw) \ + A(size_ns) \ + A(size_nwse) \ + A(size_we) \ A(software) \ A(state) \ A(sym) \ @@ -108,6 +121,8 @@ A(vertical) \ A(video) \ A(w) \ + A(wait) \ + A(wait_arrow) \ A(which) \ A(window) \ A(window_id) \ @@ -175,6 +190,16 @@ F(is_text_input_active, 0) \ F(start_text_input, 0) \ F(stop_text_input, 0) \ + /* sdl_mouse */ \ + F(capture_mouse, 1) \ + F(get_global_mouse_state, 0) \ + F(get_mouse_focus, 0) \ + F(get_mouse_state, 0) \ + F(get_relative_mouse_mode, 0) \ + F(get_relative_mouse_state, 0) \ + F(set_relative_mouse_mode, 1) \ + F(warp_mouse_global, 2) \ + F(warp_mouse_in_window, 3) \ /* sdl_power */ \ F(get_power_info, 0) \ /* sdl_renderer */ \ @@ -265,6 +290,18 @@ NIF_ENUM_TO_ATOM_FUNCTION_DECL(blend_mode_to_atom, SDL_BlendMode) // -- +void esdl2_windows_init(void); +void esdl2_windows_insert(SDL_Window*, obj_Window*); +ERL_NIF_TERM esdl2_windows_find(ErlNifEnv*, SDL_Window*); +void esdl2_windows_remove(SDL_Window*); +void esdl2_windows_free(void); + +void esdl2_renderers_init(void); +void esdl2_renderers_insert(SDL_Renderer*, obj_Renderer*, obj_Window*); +ERL_NIF_TERM esdl2_renderers_find(ErlNifEnv*, SDL_Renderer*); +void esdl2_renderers_remove(SDL_Renderer*); +void esdl2_renderers_free(void); + ErlNifPid* get_callback_process(void); #define sdl_error_tuple(env) \ diff --git a/c_src/esdl2_renderers.c b/c_src/esdl2_renderers.c new file mode 100644 index 0000000..281079c --- /dev/null +++ b/c_src/esdl2_renderers.c @@ -0,0 +1,104 @@ +// Copyright (c) 2017, Loïc Hoguin +// +// 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. +// +// THE 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. + +#include "esdl2.h" +#include + +struct esdl2_renderer { + LIST_ENTRY(esdl2_renderer) entries; + + SDL_Renderer* renderer; + obj_Renderer* res; + obj_Window* window_res; +}; + +static LIST_HEAD(esdl2_renderer_list, esdl2_renderer) renderers; + +void esdl2_renderers_init() +{ + LIST_INIT(&renderers); +} + +void esdl2_renderers_insert(SDL_Renderer* renderer, obj_Renderer* res, obj_Window* window_res) +{ + struct esdl2_renderer* item; + + item = malloc(sizeof(struct esdl2_renderer)); + item->renderer = renderer; + item->res = res; + item->window_res = window_res; + + enif_keep_resource(window_res); + + LIST_INSERT_HEAD(&renderers, item, entries); +} + +struct esdl2_renderer* esdl2_renderers_find_entry(SDL_Renderer* renderer); + +struct esdl2_renderer* esdl2_renderers_find_entry(SDL_Renderer* renderer) +{ + struct esdl2_renderer* head; + + head = LIST_FIRST(&renderers); + while (head != NULL) { + if (head->renderer == renderer) + return head; + + head = LIST_NEXT(head, entries); + } + + return NULL; +} + +ERL_NIF_TERM esdl2_renderers_find(ErlNifEnv* env, SDL_Renderer* renderer) +{ + struct esdl2_renderer* entry; + ERL_NIF_TERM term; + + entry = esdl2_renderers_find_entry(renderer); + + if (entry == NULL) + return atom_undefined; + + term = enif_make_resource(env, entry->res); + + return term; +} + +void esdl2_renderers_remove(SDL_Renderer* renderer) +{ + struct esdl2_renderer* entry; + + entry = esdl2_renderers_find_entry(renderer); + + if (entry == NULL) + return; + + enif_release_resource(entry->window_res); + + LIST_REMOVE(entry, entries); +} + +void esdl2_renderers_free() +{ + struct esdl2_renderer *head, *next; + + head = LIST_FIRST(&renderers); + while (head != NULL) { + next = LIST_NEXT(head, entries); + free(head); + head = next; + } +} + diff --git a/c_src/esdl2_windows.c b/c_src/esdl2_windows.c new file mode 100644 index 0000000..8855987 --- /dev/null +++ b/c_src/esdl2_windows.c @@ -0,0 +1,97 @@ +// Copyright (c) 2017, Loïc Hoguin +// +// 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. +// +// THE 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. + +#include "esdl2.h" +#include + +struct esdl2_window { + LIST_ENTRY(esdl2_window) entries; + + SDL_Window* window; + obj_Window* res; +}; + +static LIST_HEAD(esdl2_window_list, esdl2_window) windows; + +void esdl2_windows_init() +{ + LIST_INIT(&windows); +} + +void esdl2_windows_insert(SDL_Window* window, obj_Window* res) +{ + struct esdl2_window* item; + + item = malloc(sizeof(struct esdl2_window)); + item->window = window; + item->res = res; + + LIST_INSERT_HEAD(&windows, item, entries); +} + +struct esdl2_window* esdl2_windows_find_entry(SDL_Window* window); + +struct esdl2_window* esdl2_windows_find_entry(SDL_Window* window) +{ + struct esdl2_window* head; + + head = LIST_FIRST(&windows); + while (head != NULL) { + if (head->window == window) + return head; + + head = LIST_NEXT(head, entries); + } + + return NULL; +} + +ERL_NIF_TERM esdl2_windows_find(ErlNifEnv* env, SDL_Window* window) +{ + struct esdl2_window* entry; + ERL_NIF_TERM term; + + entry = esdl2_windows_find_entry(window); + + if (entry == NULL) + return atom_undefined; + + term = enif_make_resource(env, entry->res); + + return term; +} + +void esdl2_windows_remove(SDL_Window* window) +{ + struct esdl2_window* entry; + + entry = esdl2_windows_find_entry(window); + + if (entry == NULL) + return; + + LIST_REMOVE(entry, entries); +} + +void esdl2_windows_free() +{ + struct esdl2_window *head, *next; + + head = LIST_FIRST(&windows); + while (head != NULL) { + next = LIST_NEXT(head, entries); + free(head); + head = next; + } +} diff --git a/c_src/sdl_gl.c b/c_src/sdl_gl.c index febd49f..71fef6a 100644 --- a/c_src/sdl_gl.c +++ b/c_src/sdl_gl.c @@ -17,7 +17,7 @@ void dtor_GLContext(ErlNifEnv* env, void* obj) { SDL_GL_DeleteContext(NIF_RES_GET(GLContext, obj)); - enif_release_resource(NIF_RES_DEP(GLContext, obj)); +// @todo enif_release_resource(NIF_RES_DEP(GLContext, obj)); } // gl_create_context @@ -33,7 +33,8 @@ NIF_CALL_HANDLER(thread_gl_create_context) enif_keep_resource(args[0]); - NIF_RES_TO_TERM_WITH_DEP(GLContext, context, term, args[0]); +// @todo NIF_RES_TO_TERM_WITH_DEP(GLContext, context, term, args[0]); + NIF_RES_TO_TERM(GLContext, context, term); return enif_make_tuple2(env, atom_ok, diff --git a/c_src/sdl_mouse.c b/c_src/sdl_mouse.c new file mode 100644 index 0000000..b74d088 --- /dev/null +++ b/c_src/sdl_mouse.c @@ -0,0 +1,224 @@ +// Copyright (c) 2017, Loïc Hoguin +// +// 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. +// +// THE 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. + +#include "esdl2.h" + +#define SYSTEM_CURSOR_ENUM(E) \ + E(arrow, SDL_SYSTEM_CURSOR_ARROW) \ + E(ibeam, SDL_SYSTEM_CURSOR_IBEAM) \ + E(wait, SDL_SYSTEM_CURSOR_WAIT) \ + E(crosshair, SDL_SYSTEM_CURSOR_CROSSHAIR) \ + E(wait_arrow, SDL_SYSTEM_CURSOR_WAITARROW) \ + E(size_nwse, SDL_SYSTEM_CURSOR_SIZENWSE) \ + E(size_nesw, SDL_SYSTEM_CURSOR_SIZENESW) \ + E(size_we, SDL_SYSTEM_CURSOR_SIZEWE) \ + E(size_ns, SDL_SYSTEM_CURSOR_SIZENS) \ + E(size_all, SDL_SYSTEM_CURSOR_SIZEALL) \ + E(no, SDL_SYSTEM_CURSOR_NO) \ + E(hand, SDL_SYSTEM_CURSOR_HAND) + +static NIF_ATOM_TO_ENUM_FUNCTION(atom_to_system_cursor, int, SYSTEM_CURSOR_ENUM) + +#define MOUSEWHEEL_DIRECTION_ENUM(E) \ + E(normal, SDL_MOUSEWHEEL_NORMAL) \ + E(flipped, SDL_MOUSEWHEEL_FLIPPED) + +static NIF_ATOM_TO_ENUM_FUNCTION(atom_to_mousewheel_direction, int, MOUSEWHEEL_DIRECTION_ENUM) + +static ERL_NIF_TERM get_mouse_state_common(ErlNifEnv* env, int x, int y, Uint32 state) +{ + ERL_NIF_TERM list; + + list = enif_make_list(env, 0); + + if (state & SDL_BUTTON_LMASK) + list = enif_make_list_cell(env, atom_left, list); + if (state & SDL_BUTTON_MMASK) + list = enif_make_list_cell(env, atom_middle, list); + if (state & SDL_BUTTON_RMASK) + list = enif_make_list_cell(env, atom_right, list); + if (state & SDL_BUTTON_X1MASK) + list = enif_make_list_cell(env, atom_x1, list); + if (state & SDL_BUTTON_X2MASK) + list = enif_make_list_cell(env, atom_x2, list); + + return enif_make_tuple3(env, + enif_make_int(env, x), + enif_make_int(env, y), + list + ); +} + +// capture_mouse + +NIF_CALL_HANDLER(thread_capture_mouse) +{ + if (SDL_CaptureMouse((long)args[0])) + return sdl_error_tuple(env); + + return atom_ok; +} + +NIF_FUNCTION(capture_mouse) +{ + SDL_bool b; + + BADARG_IF(!atom_to_bool(env, argv[0], &b)); + + return nif_thread_call(env, thread_capture_mouse, 1, b); +} + +// get_global_mouse_state + +NIF_CALL_HANDLER(thread_get_global_mouse_state) +{ + Uint32 state; + int x, y; + + state = SDL_GetGlobalMouseState(&x, &y); + + return get_mouse_state_common(env, x, y, state); +} + +NIF_FUNCTION(get_global_mouse_state) +{ + return nif_thread_call(env, thread_get_global_mouse_state, 0); +} + +// get_mouse_focus + +NIF_CALL_HANDLER(thread_get_mouse_focus) +{ + SDL_Window* window; + + window = SDL_GetMouseFocus(); + + if (!window) + return atom_undefined; + + return esdl2_windows_find(env, window); +} + +NIF_FUNCTION(get_mouse_focus) +{ + return nif_thread_call(env, thread_get_mouse_focus, 0); +} + +// get_mouse_state + +NIF_CALL_HANDLER(thread_get_mouse_state) +{ + Uint32 state; + int x, y; + + state = SDL_GetMouseState(&x, &y); + + return get_mouse_state_common(env, x, y, state); +} + +NIF_FUNCTION(get_mouse_state) +{ + return nif_thread_call(env, thread_get_mouse_state, 0); +} + +// get_relative_mouse_mode + +NIF_CALL_HANDLER(thread_get_relative_mouse_mode) +{ + if (SDL_GetRelativeMouseMode()) + return atom_true; + + return atom_false; +} + +NIF_FUNCTION(get_relative_mouse_mode) +{ + return nif_thread_call(env, thread_get_relative_mouse_mode, 0); +} + +// get_relative_mouse_state + +NIF_CALL_HANDLER(thread_get_relative_mouse_state) +{ + Uint32 state; + int x, y; + + state = SDL_GetRelativeMouseState(&x, &y); + + return get_mouse_state_common(env, x, y, state); +} + +NIF_FUNCTION(get_relative_mouse_state) +{ + return nif_thread_call(env, thread_get_relative_mouse_state, 0); +} + +// set_relative_mouse_mode + +NIF_CALL_HANDLER(thread_set_relative_mouse_mode) +{ + if (SDL_SetRelativeMouseMode((long)args[0])) + return sdl_error_tuple(env); + + return atom_ok; +} + +NIF_FUNCTION(set_relative_mouse_mode) +{ + SDL_bool b; + + BADARG_IF(!atom_to_bool(env, argv[0], &b)); + + return nif_thread_call(env, thread_set_relative_mouse_mode, 1, b); +} + +// warp_mouse_global + +NIF_CALL_HANDLER(thread_warp_mouse_global) +{ + if (SDL_WarpMouseGlobal((long)args[0], (long)args[1])) + return sdl_error_tuple(env); + + return atom_ok; +} + +NIF_FUNCTION(warp_mouse_global) +{ + int x, y; + + BADARG_IF(!enif_get_int(env, argv[0], &x)); + BADARG_IF(!enif_get_int(env, argv[1], &y)); + + return nif_thread_call(env, thread_warp_mouse_global, 2, x, y); +} + +// warp_mouse_in_window + +NIF_CAST_HANDLER(thread_warp_mouse_in_window) +{ + SDL_WarpMouseInWindow(args[0], (long)args[1], (long)args[2]); +} + +NIF_FUNCTION(warp_mouse_in_window) +{ + void* window_res; + int x, y; + + BADARG_IF(!enif_get_resource(env, argv[0], res_Window, &window_res)); + BADARG_IF(!enif_get_int(env, argv[1], &x)); + BADARG_IF(!enif_get_int(env, argv[2], &y)); + + return nif_thread_cast(env, thread_warp_mouse_in_window, 3, + NIF_RES_GET(Window, window_res), x, y); +} diff --git a/c_src/sdl_renderer.c b/c_src/sdl_renderer.c index 5344199..81e60c4 100644 --- a/c_src/sdl_renderer.c +++ b/c_src/sdl_renderer.c @@ -16,8 +16,10 @@ void dtor_Renderer(ErlNifEnv* env, void* obj) { - SDL_DestroyRenderer(NIF_RES_GET(Renderer, obj)); - enif_release_resource(NIF_RES_DEP(Renderer, obj)); + SDL_Renderer* renderer = NIF_RES_GET(Renderer, obj); + + SDL_DestroyRenderer(renderer); + esdl2_renderers_remove(renderer); } #define RENDERER_FLAGS(F) \ @@ -91,14 +93,16 @@ static int map_to_rect(ErlNifEnv* env, ERL_NIF_TERM map, SDL_Rect* rect) NIF_CALL_HANDLER(thread_create_renderer) { SDL_Renderer* renderer; + obj_Renderer* res; ERL_NIF_TERM term; renderer = SDL_CreateRenderer(NIF_RES_GET(Window, args[0]), (long)args[1], (long)args[2]); if (!renderer) return sdl_error_tuple(env); - enif_keep_resource(args[0]); - NIF_RES_TO_TERM_WITH_DEP(Renderer, renderer, term, args[0]); + NIF_RES_TO_PTR_AND_TERM(Renderer, renderer, res, term); + + esdl2_renderers_insert(renderer, res, args[0]); return enif_make_tuple2(env, atom_ok, diff --git a/c_src/sdl_window.c b/c_src/sdl_window.c index ef3647b..c286da0 100644 --- a/c_src/sdl_window.c +++ b/c_src/sdl_window.c @@ -14,9 +14,13 @@ #include "esdl2.h" +// @todo These operations should probably occur in the thread. void dtor_Window(ErlNifEnv* env, void* obj) { - SDL_DestroyWindow(NIF_RES_GET(Window, obj)); + SDL_Window* window = NIF_RES_GET(Window, obj); + + SDL_DestroyWindow(window); + esdl2_windows_remove(window); } #define WINDOW_FLAGS(F) \ @@ -33,7 +37,8 @@ void dtor_Window(ErlNifEnv* env, void* obj) F(input_focus, SDL_WINDOW_INPUT_FOCUS) \ F(mouse_focus, SDL_WINDOW_MOUSE_FOCUS) \ F(foreign, SDL_WINDOW_FOREIGN) \ - F(allow_high_dpi, SDL_WINDOW_ALLOW_HIGHDPI) + F(allow_high_dpi, SDL_WINDOW_ALLOW_HIGHDPI) \ + F(mouse_capture, SDL_WINDOW_MOUSE_CAPTURE) static NIF_LIST_TO_FLAGS_FUNCTION(list_to_window_flags, Uint32, WINDOW_FLAGS) static NIF_FLAGS_TO_LIST_FUNCTION(window_flags_to_list, Uint32, WINDOW_FLAGS) @@ -56,6 +61,7 @@ static NIF_ATOM_TO_ENUM_FUNCTION(atom_to_window_fullscreen, Uint32, WINDOW_FULLS NIF_CALL_HANDLER(thread_create_window) { SDL_Window* window; + obj_Window* res; ERL_NIF_TERM term; window = SDL_CreateWindow(args[0], (long)args[1], (long)args[2], (long)args[3], (long)args[4], (long)args[5]); @@ -65,7 +71,9 @@ NIF_CALL_HANDLER(thread_create_window) if (!window) return sdl_error_tuple(env); - NIF_RES_TO_TERM(Window, window, term); + NIF_RES_TO_PTR_AND_TERM(Window, window, res, term); + + esdl2_windows_insert(window, res); return enif_make_tuple2(env, atom_ok, diff --git a/ebin/esdl2.app b/ebin/esdl2.app index c794a76..7439c29 100644 --- a/ebin/esdl2.app +++ b/ebin/esdl2.app @@ -1,7 +1,7 @@ {application, 'esdl2', [ {description, "SDL2 Erlang NIF."}, {vsn, "0.1.0"}, - {modules, ['esdl2','esdl2_app','esdl2_callbacks','esdl2_sup','sdl','sdl_clipboard','sdl_cpu_info','sdl_events','sdl_filesystem','sdl_gl','sdl_hints','sdl_keyboard','sdl_power','sdl_renderer','sdl_surface','sdl_texture','sdl_version','sdl_window']}, + {modules, ['esdl2','esdl2_app','esdl2_callbacks','esdl2_sup','sdl','sdl_clipboard','sdl_cpu_info','sdl_events','sdl_filesystem','sdl_gl','sdl_hints','sdl_keyboard','sdl_mouse','sdl_power','sdl_renderer','sdl_surface','sdl_texture','sdl_version','sdl_window']}, {registered, [esdl2_sup]}, {applications, [kernel,stdlib]}, {mod, {esdl2_app, []}}, diff --git a/erlang.mk b/erlang.mk index 64aaa4e..e3b4664 100644 --- a/erlang.mk +++ b/erlang.mk @@ -15,8 +15,10 @@ .PHONY: all app apps deps search rel relup docs install-docs check tests clean distclean help erlang-mk ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) +export ERLANG_MK_FILENAME -ERLANG_MK_VERSION = 2017.04.25-6-g5922969 +ERLANG_MK_VERSION = 2017.08.28-22-gf545564 +ERLANG_MK_WITHOUT = # Make 3.81 and 3.82 are deprecated. @@ -183,19 +185,101 @@ ERLANG_MK_COMMIT ?= ERLANG_MK_BUILD_CONFIG ?= build.config ERLANG_MK_BUILD_DIR ?= .erlang.mk.build +erlang-mk: WITHOUT ?= $(ERLANG_MK_WITHOUT) erlang-mk: git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) ifdef ERLANG_MK_COMMIT cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) endif if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi - $(MAKE) -C $(ERLANG_MK_BUILD_DIR) + $(MAKE) -C $(ERLANG_MK_BUILD_DIR) WITHOUT='$(strip $(WITHOUT))' cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk rm -rf $(ERLANG_MK_BUILD_DIR) # The erlang.mk package index is bundled in the default erlang.mk build. # Search for the string "copyright" to skip to the rest of the code. +# Copyright (c) 2015-2017, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-kerl + +KERL_INSTALL_DIR ?= $(HOME)/erlang + +ifeq ($(strip $(KERL)),) +KERL := $(ERLANG_MK_TMP)/kerl/kerl +endif + +export KERL + +KERL_GIT ?= https://github.com/kerl/kerl +KERL_COMMIT ?= master + +KERL_MAKEFLAGS ?= + +OTP_GIT ?= https://github.com/erlang/otp + +define kerl_otp_target +ifeq ($(wildcard $(KERL_INSTALL_DIR)/$(1)),) +$(KERL_INSTALL_DIR)/$(1): $(KERL) + MAKEFLAGS="$(KERL_MAKEFLAGS)" $(KERL) build git $(OTP_GIT) $(1) $(1) + $(KERL) install $(1) $(KERL_INSTALL_DIR)/$(1) +endif +endef + +define kerl_hipe_target +ifeq ($(wildcard $(KERL_INSTALL_DIR)/$1-native),) +$(KERL_INSTALL_DIR)/$1-native: $(KERL) + KERL_CONFIGURE_OPTIONS=--enable-native-libs \ + MAKEFLAGS="$(KERL_MAKEFLAGS)" $(KERL) build git $(OTP_GIT) $1 $1-native + $(KERL) install $1-native $(KERL_INSTALL_DIR)/$1-native +endif +endef + +$(KERL): + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(gen_verbose) git clone --depth 1 $(KERL_GIT) $(ERLANG_MK_TMP)/kerl + $(verbose) cd $(ERLANG_MK_TMP)/kerl && git checkout $(KERL_COMMIT) + $(verbose) chmod +x $(KERL) + +distclean:: distclean-kerl + +distclean-kerl: + $(gen_verbose) rm -rf $(KERL) + +# Allow users to select which version of Erlang/OTP to use for a project. + +ERLANG_OTP ?= +ERLANG_HIPE ?= + +# Use kerl to enforce a specific Erlang/OTP version for a project. +ifneq ($(strip $(ERLANG_OTP)),) +export PATH := $(KERL_INSTALL_DIR)/$(ERLANG_OTP)/bin:$(PATH) +SHELL := env PATH=$(PATH) $(SHELL) +$(eval $(call kerl_otp_target,$(ERLANG_OTP))) + +# Build Erlang/OTP only if it doesn't already exist. +ifeq ($(wildcard $(KERL_INSTALL_DIR)/$(ERLANG_OTP))$(BUILD_ERLANG_OTP),) +$(info Building Erlang/OTP $(ERLANG_OTP)... Please wait...) +$(shell $(MAKE) $(KERL_INSTALL_DIR)/$(ERLANG_OTP) ERLANG_OTP=$(ERLANG_OTP) BUILD_ERLANG_OTP=1 >&2) +endif + +else +# Same for a HiPE enabled VM. +ifneq ($(strip $(ERLANG_HIPE)),) +export PATH := $(KERL_INSTALL_DIR)/$(ERLANG_HIPE)-native/bin:$(PATH) +SHELL := env PATH=$(PATH) $(SHELL) +$(eval $(call kerl_hipe_target,$(ERLANG_HIPE))) + +# Build Erlang/OTP only if it doesn't already exist. +ifeq ($(wildcard $(KERL_INSTALL_DIR)/$(ERLANG_HIPE))$(BUILD_ERLANG_OTP),) +$(info Building HiPE-enabled Erlang/OTP $(ERLANG_OTP)... Please wait...) +$(shell $(MAKE) $(KERL_INSTALL_DIR)/$(ERLANG_HIPE) ERLANG_HIPE=$(ERLANG_HIPE) BUILD_ERLANG_OTP=1 >&2) +endif + +endif +endif + PACKAGES += aberth pkg_aberth_name = aberth pkg_aberth_description = Generic BERT-RPC server in Erlang @@ -532,14 +616,6 @@ pkg_cl_fetch = git pkg_cl_repo = https://github.com/tonyrog/cl pkg_cl_commit = master -PACKAGES += classifier -pkg_classifier_name = classifier -pkg_classifier_description = An Erlang Bayesian Filter and Text Classifier -pkg_classifier_homepage = https://github.com/inaka/classifier -pkg_classifier_fetch = git -pkg_classifier_repo = https://github.com/inaka/classifier -pkg_classifier_commit = master - PACKAGES += clique pkg_clique_name = clique pkg_clique_description = CLI Framework for Erlang @@ -940,14 +1016,6 @@ pkg_dnssd_fetch = git pkg_dnssd_repo = https://github.com/benoitc/dnssd_erlang pkg_dnssd_commit = master -PACKAGES += dtl -pkg_dtl_name = dtl -pkg_dtl_description = Django Template Language: A full-featured port of the Django template engine to Erlang. -pkg_dtl_homepage = https://github.com/oinksoft/dtl -pkg_dtl_fetch = git -pkg_dtl_repo = https://github.com/oinksoft/dtl -pkg_dtl_commit = master - PACKAGES += dynamic_compile pkg_dynamic_compile_name = dynamic_compile pkg_dynamic_compile_description = compile and load erlang modules from string input @@ -1516,6 +1584,14 @@ pkg_erwa_fetch = git pkg_erwa_repo = https://github.com/bwegh/erwa pkg_erwa_commit = master +PACKAGES += escalus +pkg_escalus_name = escalus +pkg_escalus_description = An XMPP client library in Erlang for conveniently testing XMPP servers +pkg_escalus_homepage = https://github.com/esl/escalus +pkg_escalus_fetch = git +pkg_escalus_repo = https://github.com/esl/escalus +pkg_escalus_commit = master + PACKAGES += espec pkg_espec_name = espec pkg_espec_description = ESpec: Behaviour driven development framework for Erlang @@ -1908,14 +1984,6 @@ pkg_gold_fever_fetch = git pkg_gold_fever_repo = https://github.com/inaka/gold_fever pkg_gold_fever_commit = master -PACKAGES += gossiperl -pkg_gossiperl_name = gossiperl -pkg_gossiperl_description = Gossip middleware in Erlang -pkg_gossiperl_homepage = http://gossiperl.com/ -pkg_gossiperl_fetch = git -pkg_gossiperl_repo = https://github.com/gossiperl/gossiperl -pkg_gossiperl_commit = master - PACKAGES += gpb pkg_gpb_name = gpb pkg_gpb_description = A Google Protobuf implementation for Erlang @@ -1940,6 +2008,22 @@ pkg_grapherl_fetch = git pkg_grapherl_repo = https://github.com/eproxus/grapherl pkg_grapherl_commit = master +PACKAGES += grpc +pkg_grpc_name = grpc +pkg_grpc_description = gRPC server in Erlang +pkg_grpc_homepage = https://github.com/Bluehouse-Technology/grpc +pkg_grpc_fetch = git +pkg_grpc_repo = https://github.com/Bluehouse-Technology/grpc +pkg_grpc_commit = master + +PACKAGES += grpc_client +pkg_grpc_client_name = grpc_client +pkg_grpc_client_description = gRPC client in Erlang +pkg_grpc_client_homepage = https://github.com/Bluehouse-Technology/grpc_client +pkg_grpc_client_fetch = git +pkg_grpc_client_repo = https://github.com/Bluehouse-Technology/grpc_client +pkg_grpc_client_commit = master + PACKAGES += gun pkg_gun_name = gun pkg_gun_description = Asynchronous SPDY, HTTP and Websocket client written in Erlang. @@ -2020,6 +2104,14 @@ pkg_ibrowse_fetch = git pkg_ibrowse_repo = https://github.com/cmullaparthi/ibrowse pkg_ibrowse_commit = master +PACKAGES += idna +pkg_idna_name = idna +pkg_idna_description = Erlang IDNA lib +pkg_idna_homepage = https://github.com/benoitc/erlang-idna +pkg_idna_fetch = git +pkg_idna_repo = https://github.com/benoitc/erlang-idna +pkg_idna_commit = master + PACKAGES += ierlang pkg_ierlang_name = ierlang pkg_ierlang_description = An Erlang language kernel for IPython. @@ -2295,9 +2387,9 @@ pkg_kvs_commit = master PACKAGES += lager pkg_lager_name = lager pkg_lager_description = A logging framework for Erlang/OTP. -pkg_lager_homepage = https://github.com/basho/lager +pkg_lager_homepage = https://github.com/erlang-lager/lager pkg_lager_fetch = git -pkg_lager_repo = https://github.com/basho/lager +pkg_lager_repo = https://github.com/erlang-lager/lager pkg_lager_commit = master PACKAGES += lager_amqp_backend @@ -2311,9 +2403,9 @@ pkg_lager_amqp_backend_commit = master PACKAGES += lager_syslog pkg_lager_syslog_name = lager_syslog pkg_lager_syslog_description = Syslog backend for lager -pkg_lager_syslog_homepage = https://github.com/basho/lager_syslog +pkg_lager_syslog_homepage = https://github.com/erlang-lager/lager_syslog pkg_lager_syslog_fetch = git -pkg_lager_syslog_repo = https://github.com/basho/lager_syslog +pkg_lager_syslog_repo = https://github.com/erlang-lager/lager_syslog pkg_lager_syslog_commit = master PACKAGES += lambdapad @@ -3604,6 +3696,14 @@ pkg_stripe_fetch = git pkg_stripe_repo = https://github.com/mattsta/stripe-erlang pkg_stripe_commit = v1 +PACKAGES += subproc +pkg_subproc_name = subproc +pkg_subproc_description = unix subprocess manager with {active,once|false} modes +pkg_subproc_homepage = http://dozzie.jarowit.net/trac/wiki/subproc +pkg_subproc_fetch = git +pkg_subproc_repo = https://github.com/dozzie/subproc +pkg_subproc_commit = v0.1.0 + PACKAGES += supervisor3 pkg_supervisor3_name = supervisor3 pkg_supervisor3_description = OTP supervisor with additional strategies @@ -3732,6 +3832,14 @@ pkg_tirerl_fetch = git pkg_tirerl_repo = https://github.com/inaka/tirerl pkg_tirerl_commit = master +PACKAGES += toml +pkg_toml_name = toml +pkg_toml_description = TOML (0.4.0) config parser +pkg_toml_homepage = http://dozzie.jarowit.net/trac/wiki/TOML +pkg_toml_fetch = git +pkg_toml_repo = https://github.com/dozzie/toml +pkg_toml_commit = v0.2.0 + PACKAGES += traffic_tools pkg_traffic_tools_name = traffic_tools pkg_traffic_tools_description = Simple traffic limiting library @@ -3775,9 +3883,9 @@ pkg_trie_commit = master PACKAGES += triq pkg_triq_name = triq pkg_triq_description = Trifork QuickCheck -pkg_triq_homepage = https://github.com/krestenkrab/triq +pkg_triq_homepage = https://github.com/triqng/triq pkg_triq_fetch = git -pkg_triq_repo = https://github.com/krestenkrab/triq +pkg_triq_repo = https://github.com/triqng/triq.git pkg_triq_commit = master PACKAGES += tunctl @@ -4118,6 +4226,26 @@ export DEPS_DIR REBAR_DEPS_DIR = $(DEPS_DIR) export REBAR_DEPS_DIR +# External "early" plugins (see core/plugins.mk for regular plugins). +# They both use the core_dep_plugin macro. + +define core_dep_plugin +ifeq ($(2),$(PROJECT)) +-include $$(patsubst $(PROJECT)/%,%,$(1)) +else +-include $(DEPS_DIR)/$(1) + +$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; +endif +endef + +DEP_EARLY_PLUGINS ?= + +$(foreach p,$(DEP_EARLY_PLUGINS),\ + $(eval $(if $(findstring /,$p),\ + $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ + $(call core_dep_plugin,$p/early-plugins.mk,$p)))) + dep_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) dep_repo = $(patsubst git://github.com/%,https://github.com/%, \ $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))) @@ -4155,19 +4283,19 @@ endif # as proper OTP applications when using -include_lib. This is a temporary # fix, a proper fix would be to compile apps/* in the right order. ifndef IS_APP - $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ - mkdir -p $$dep/ebin || exit $$?; \ + $(verbose) set -e; for dep in $(ALL_APPS_DIRS) ; do \ + mkdir -p $$dep/ebin; \ done endif # at the toplevel: if LOCAL_DEPS is defined with at least one local app, only # compile that list of apps. otherwise, compile everything. # within an app: compile all LOCAL_DEPS that are (uncompiled) local apps - $(verbose) for dep in $(if $(LOCAL_DEPS_DIRS)$(IS_APP),$(LOCAL_DEPS_DIRS),$(ALL_APPS_DIRS)) ; do \ + $(verbose) set -e; for dep in $(if $(LOCAL_DEPS_DIRS)$(IS_APP),$(LOCAL_DEPS_DIRS),$(ALL_APPS_DIRS)) ; do \ if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \ :; \ else \ echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \ - $(MAKE) -C $$dep IS_APP=1 || exit $$?; \ + $(MAKE) -C $$dep IS_APP=1; \ fi \ done @@ -4181,15 +4309,15 @@ deps:: else deps:: $(ALL_DEPS_DIRS) apps clean-tmp-deps.log $(verbose) mkdir -p $(ERLANG_MK_TMP) - $(verbose) for dep in $(ALL_DEPS_DIRS) ; do \ + $(verbose) set -e; for dep in $(ALL_DEPS_DIRS) ; do \ if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ :; \ else \ echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ - $(MAKE) -C $$dep IS_DEP=1 || exit $$?; \ + $(MAKE) -C $$dep IS_DEP=1; \ else \ - echo "Error: No Makefile to build dependency $$dep."; \ + echo "Error: No Makefile to build dependency $$dep." >&2; \ exit 2; \ fi \ fi \ @@ -4226,6 +4354,7 @@ define dep_autopatch endef define dep_autopatch2 + ! test -f $(DEPS_DIR)/$1/ebin/$1.app || \ mv -n $(DEPS_DIR)/$1/ebin/$1.app $(DEPS_DIR)/$1/src/$1.app.src; \ rm -f $(DEPS_DIR)/$1/ebin/$1.app; \ if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ @@ -4244,11 +4373,15 @@ define dep_autopatch_noop printf "noop:\n" > $(DEPS_DIR)/$(1)/Makefile endef -# Overwrite erlang.mk with the current file by default. +# Replace "include erlang.mk" with a line that will load the parent Erlang.mk +# if given. Do it for all 3 possible Makefile file names. ifeq ($(NO_AUTOPATCH_ERLANG_MK),) define dep_autopatch_erlang_mk - echo "include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk" \ - > $(DEPS_DIR)/$1/erlang.mk + for f in Makefile makefile GNUmakefile; do \ + if [ -f $(DEPS_DIR)/$1/$$f ]; then \ + sed -i.bak s/'include *erlang.mk'/'include $$(if $$(ERLANG_MK_FILENAME),$$(ERLANG_MK_FILENAME),erlang.mk)'/ $(DEPS_DIR)/$1/$$f; \ + fi \ + done endef else define dep_autopatch_erlang_mk @@ -4313,6 +4446,10 @@ define dep_autopatch_rebar.erl Write("C_SRC_TYPE = rebar\n"), Write("DRV_CFLAGS = -fPIC\nexport DRV_CFLAGS\n"), Write(["ERLANG_ARCH = ", rebar_utils:wordsize(), "\nexport ERLANG_ARCH\n"]), + ToList = fun + (V) when is_atom(V) -> atom_to_list(V); + (V) when is_list(V) -> "'\\"" ++ V ++ "\\"'" + end, fun() -> Write("ERLC_OPTS = +debug_info\nexport ERLC_OPTS\n"), case lists:keyfind(erl_opts, 1, Conf) of @@ -4320,16 +4457,18 @@ define dep_autopatch_rebar.erl {_, ErlOpts} -> lists:foreach(fun ({d, D}) -> - Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + Write("ERLC_OPTS += -D" ++ ToList(D) ++ "=1\n"); + ({d, DKey, DVal}) -> + Write("ERLC_OPTS += -D" ++ ToList(DKey) ++ "=" ++ ToList(DVal) ++ "\n"); ({i, I}) -> Write(["ERLC_OPTS += -I ", I, "\n"]); ({platform_define, Regex, D}) -> case rebar_utils:is_arch(Regex) of - true -> Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + true -> Write("ERLC_OPTS += -D" ++ ToList(D) ++ "=1\n"); false -> ok end; ({parse_transform, PT}) -> - Write("ERLC_OPTS += +'{parse_transform, " ++ atom_to_list(PT) ++ "}'\n"); + Write("ERLC_OPTS += +'{parse_transform, " ++ ToList(PT) ++ "}'\n"); (_) -> ok end, ErlOpts) end, @@ -4491,7 +4630,7 @@ define dep_autopatch_rebar.erl end, [PortSpec(S) || S <- PortSpecs] end, - Write("\ninclude $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk"), + Write("\ninclude $$\(if $$\(ERLANG_MK_FILENAME),$$\(ERLANG_MK_FILENAME),erlang.mk)"), RunPlugin = fun(Plugin, Step) -> case erlang:function_exported(Plugin, Step, 2) of false -> ok; @@ -4542,8 +4681,11 @@ endef define dep_autopatch_appsrc_script.erl AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", AppSrcScript = AppSrc ++ ".script", - Bindings = erl_eval:new_bindings(), - {ok, Conf} = file:script(AppSrcScript, Bindings), + {ok, Conf0} = file:consult(AppSrc), + Bindings0 = erl_eval:new_bindings(), + Bindings1 = erl_eval:add_binding('CONFIG', Conf0, Bindings0), + Bindings = erl_eval:add_binding('SCRIPT', AppSrcScript, Bindings1), + {ok, [Conf]} = file:script(AppSrcScript, Bindings), ok = file:write_file(AppSrc, io_lib:format("~p.~n", [Conf])), halt() endef @@ -4556,7 +4698,11 @@ define dep_autopatch_appsrc.erl true -> {ok, [{application, $(1), L0}]} = file:consult(AppSrcIn), L1 = lists:keystore(modules, 1, L0, {modules, []}), - L2 = case lists:keyfind(vsn, 1, L1) of {_, git} -> lists:keyreplace(vsn, 1, L1, {vsn, "git"}); _ -> L1 end, + L2 = case lists:keyfind(vsn, 1, L1) of + {_, git} -> lists:keyreplace(vsn, 1, L1, {vsn, "git"}); + {_, {cmd, _}} -> lists:keyreplace(vsn, 1, L1, {vsn, "cmd"}); + _ -> L1 + end, L3 = case lists:keyfind(registered, 1, L2) of false -> [{registered, []}|L2]; _ -> L2 end, ok = file:write_file(AppSrcOut, io_lib:format("~p.~n", [{application, $(1), L3}])), case AppSrcOut of AppSrcIn -> ok; _ -> ok = file:delete(AppSrcIn) end @@ -4586,6 +4732,10 @@ define dep_fetch_cp cp -R $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); endef +define dep_fetch_ln + ln -s $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + # Hex only has a package version. No need to look in the Erlang.mk packages. define dep_fetch_hex mkdir -p $(ERLANG_MK_TMP)/hex $(DEPS_DIR)/$1; \ @@ -4621,7 +4771,7 @@ $(DEPS_DIR)/$(call dep_name,$1): $(eval DEP_NAME := $(call dep_name,$1)) $(eval DEP_STR := $(if $(filter-out $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) $(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \ - echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)."; \ + echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)." >&2; \ exit 17; \ fi $(verbose) mkdir -p $(DEPS_DIR) @@ -4663,15 +4813,15 @@ ifndef IS_APP clean:: clean-apps clean-apps: - $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ - $(MAKE) -C $$dep clean IS_APP=1 || exit $$?; \ + $(verbose) set -e; for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep clean IS_APP=1; \ done distclean:: distclean-apps distclean-apps: - $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ - $(MAKE) -C $$dep distclean IS_APP=1 || exit $$?; \ + $(verbose) set -e; for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep distclean IS_APP=1; \ done endif @@ -4710,10 +4860,9 @@ endef define compile_proto.erl [begin - Dir = filename:dirname(filename:dirname(F)), protobuffs_compile:generate_source(F, - [{output_include_dir, Dir ++ "/include"}, - {output_src_dir, Dir ++ "/ebin"}]) + [{output_include_dir, "./include"}, + {output_src_dir, "./ebin"}]) end || F <- string:tokens("$(1)", " ")], halt(). endef @@ -4794,7 +4943,7 @@ define app_file {id$(comma)$(space)"$(1)"}$(comma)) {modules, [$(call comma_list,$(2))]}, {registered, []}, - {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(foreach dep,$(DEPS),$(call dep_name,$(dep))))]}, {env, $(subst \,\\,$(PROJECT_ENV))}$(if $(findstring {,$(PROJECT_APP_EXTRA_KEYS)),$(comma)$(newline)$(tab)$(subst \,\\,$(PROJECT_APP_EXTRA_KEYS)),) ]}. endef @@ -4806,7 +4955,7 @@ define app_file {id$(comma)$(space)"$(1)"}$(comma)) {modules, [$(call comma_list,$(2))]}, {registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]}, - {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(foreach dep,$(DEPS),$(call dep_name,$(dep))))]}, {mod, {$(PROJECT_MOD), []}}, {env, $(subst \,\\,$(PROJECT_ENV))}$(if $(findstring {,$(PROJECT_APP_EXTRA_KEYS)),$(comma)$(newline)$(tab)$(subst \,\\,$(PROJECT_APP_EXTRA_KEYS)),) ]}. @@ -5037,7 +5186,7 @@ ifneq ($(SKIP_DEPS),) doc-deps: else doc-deps: $(ALL_DOC_DEPS_DIRS) - $(verbose) for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done + $(verbose) set -e; for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done endif # Copyright (c) 2015-2016, Loïc Hoguin @@ -5057,7 +5206,7 @@ ifneq ($(SKIP_DEPS),) rel-deps: else rel-deps: $(ALL_REL_DEPS_DIRS) - $(verbose) for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done + $(verbose) set -e; for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done endif # Copyright (c) 2015-2016, Loïc Hoguin @@ -5082,7 +5231,7 @@ ifneq ($(SKIP_DEPS),) test-deps: else test-deps: $(ALL_TEST_DEPS_DIRS) - $(verbose) for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done + $(verbose) set -e; for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done endif ifneq ($(wildcard $(TEST_DIR)),) @@ -5227,7 +5376,7 @@ install-docs:: install-asciidoc install-asciidoc: asciidoc-manual $(foreach s,$(MAN_SECTIONS),\ mkdir -p $(MAN_INSTALL_PATH)/man$s/ && \ - install -g `id -u` -o `id -g` -m 0644 doc/man$s/*.gz $(MAN_INSTALL_PATH)/man$s/;) + install -g `id -g` -o `id -u` -m 0644 doc/man$s/*.gz $(MAN_INSTALL_PATH)/man$s/;) distclean-asciidoc-manual: $(gen_verbose) rm -rf $(addprefix doc/man,$(MAN_SECTIONS)) @@ -5927,10 +6076,10 @@ else $(call render_template,bs_erl_nif,src/$n.erl) endif -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015-2017, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. -.PHONY: ci ci-prepare ci-setup distclean-kerl +.PHONY: ci ci-prepare ci-setup CI_OTP ?= CI_HIPE ?= @@ -5948,24 +6097,9 @@ ifeq ($(strip $(CI_OTP) $(CI_HIPE) $(CI_ERLLVM)),) ci:: else -ifeq ($(strip $(KERL)),) -KERL := $(ERLANG_MK_TMP)/kerl/kerl -endif - -export KERL - -KERL_GIT ?= https://github.com/kerl/kerl -KERL_COMMIT ?= master - -KERL_MAKEFLAGS ?= - -OTP_GIT ?= https://github.com/erlang/otp - -CI_INSTALL_DIR ?= $(HOME)/erlang - ci:: $(addprefix ci-,$(CI_OTP) $(addsuffix -native,$(CI_HIPE)) $(addsuffix -erllvm,$(CI_ERLLVM))) -ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP) $(addsuffix -native,$(CI_HIPE))) +ci-prepare: $(addprefix $(KERL_INSTALL_DIR)/,$(CI_OTP) $(addsuffix -native,$(CI_HIPE))) ci-setup:: @@ -5975,10 +6109,10 @@ ci_verbose_0 = @echo " CI " $(1); ci_verbose = $(ci_verbose_$(V)) define ci_target -ci-$1: $(CI_INSTALL_DIR)/$2 +ci-$1: $(KERL_INSTALL_DIR)/$2 $(verbose) $(MAKE) --no-print-directory clean $(ci_verbose) \ - PATH="$(CI_INSTALL_DIR)/$2/bin:$(PATH)" \ + PATH="$(KERL_INSTALL_DIR)/$2/bin:$(PATH)" \ CI_OTP_RELEASE="$1" \ CT_OPTS="-label $1" \ CI_VM="$3" \ @@ -5990,32 +6124,8 @@ $(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp),$(otp),otp))) $(foreach otp,$(CI_HIPE),$(eval $(call ci_target,$(otp)-native,$(otp)-native,native))) $(foreach otp,$(CI_ERLLVM),$(eval $(call ci_target,$(otp)-erllvm,$(otp)-native,erllvm))) -define ci_otp_target -ifeq ($(wildcard $(CI_INSTALL_DIR)/$(1)),) -$(CI_INSTALL_DIR)/$(1): $(KERL) - MAKEFLAGS="$(KERL_MAKEFLAGS)" $(KERL) build git $(OTP_GIT) $(1) $(1) - $(KERL) install $(1) $(CI_INSTALL_DIR)/$(1) -endif -endef - -$(foreach otp,$(CI_OTP),$(eval $(call ci_otp_target,$(otp)))) - -define ci_hipe_target -ifeq ($(wildcard $(CI_INSTALL_DIR)/$1-native),) -$(CI_INSTALL_DIR)/$1-native: $(KERL) - KERL_CONFIGURE_OPTIONS=--enable-native-libs \ - MAKEFLAGS="$(KERL_MAKEFLAGS)" $(KERL) build git $(OTP_GIT) $1 $1-native - $(KERL) install $1-native $(CI_INSTALL_DIR)/$1-native -endif -endef - -$(foreach otp,$(sort $(CI_HIPE) $(CI_ERLLLVM)),$(eval $(call ci_hipe_target,$(otp)))) - -$(KERL): - $(verbose) mkdir -p $(ERLANG_MK_TMP) - $(gen_verbose) git clone --depth 1 $(KERL_GIT) $(ERLANG_MK_TMP)/kerl - $(verbose) cd $(ERLANG_MK_TMP)/kerl && git checkout $(KERL_COMMIT) - $(verbose) chmod +x $(KERL) +$(foreach otp,$(CI_OTP),$(eval $(call kerl_otp_target,$(otp)))) +$(foreach otp,$(sort $(CI_HIPE) $(CI_ERLLLVM)),$(eval $(call kerl_hipe_target,$(otp)))) help:: $(verbose) printf "%s\n" "" \ @@ -6025,10 +6135,6 @@ help:: "The CI_OTP variable must be defined with the Erlang versions" \ "that must be tested. For example: CI_OTP = OTP-17.3.4 OTP-17.5.3" -distclean:: distclean-kerl - -distclean-kerl: - $(gen_verbose) rm -rf $(KERL) endif # Copyright (c) 2013-2016, Loïc Hoguin @@ -6074,10 +6180,13 @@ CT_RUN = ct_run \ ifeq ($(CT_SUITES),) ct: $(if $(IS_APP),,apps-ct) else +# We do not run tests if we are in an apps/* with no test directory. +ifneq ($(IS_APP)$(wildcard $(TEST_DIR)),1) ct: test-build $(if $(IS_APP),,apps-ct) $(verbose) mkdir -p $(CT_LOGS_DIR) $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) endif +endif ifneq ($(ALL_APPS_DIRS),) define ct_app_target @@ -6181,10 +6290,21 @@ endif # Configuration. EDOC_OPTS ?= +EDOC_SRC_DIRS ?= +EDOC_OUTPUT ?= doc + +define edoc.erl + SrcPaths = lists:foldl(fun(P, Acc) -> + filelib:wildcard(atom_to_list(P) ++ "/{src,c_src}") ++ Acc + end, [], [$(call comma_list,$(patsubst %,'%',$(EDOC_SRC_DIRS)))]), + DefaultOpts = [{dir, "$(EDOC_OUTPUT)"}, {source_path, SrcPaths}, {subpackages, false}], + edoc:application($(1), ".", [$(2)] ++ DefaultOpts), + halt(0). +endef # Core targets. -ifneq ($(wildcard doc/overview.edoc),) +ifneq ($(strip $(EDOC_SRC_DIRS)$(wildcard doc/overview.edoc)),) docs:: edoc endif @@ -6193,10 +6313,10 @@ distclean:: distclean-edoc # Plugin-specific targets. edoc: distclean-edoc doc-deps - $(gen_verbose) $(ERL) -eval 'edoc:application($(PROJECT), ".", [$(EDOC_OPTS)]), halt().' + $(gen_verbose) $(call erlang,$(call edoc.erl,$(PROJECT),$(EDOC_OPTS))) distclean-edoc: - $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info + $(gen_verbose) rm -f $(EDOC_OUTPUT)/*.css $(EDOC_OUTPUT)/*.html $(EDOC_OUTPUT)/*.png $(EDOC_OUTPUT)/edoc-info # Copyright (c) 2013-2016, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. @@ -6348,7 +6468,7 @@ define eunit.erl case "$(COVER)" of "" -> ok; _ -> - cover:export("eunit.coverdata") + cover:export("$(COVER_DATA_DIR)/eunit.coverdata") end, halt() endef @@ -6357,10 +6477,10 @@ EUNIT_ERL_OPTS += -pa $(TEST_DIR) $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(CURDIR ifdef t ifeq (,$(findstring :,$(t))) -eunit: test-build +eunit: test-build cover-data-dir $(gen_verbose) $(call erlang,$(call eunit.erl,['$(t)']),$(EUNIT_ERL_OPTS)) else -eunit: test-build +eunit: test-build cover-data-dir $(gen_verbose) $(call erlang,$(call eunit.erl,fun $(t)/0),$(EUNIT_ERL_OPTS)) endif else @@ -6370,7 +6490,7 @@ EUNIT_TEST_MODS = $(notdir $(basename $(call core_find,$(TEST_DIR)/,*.erl))) EUNIT_MODS = $(foreach mod,$(EUNIT_EBIN_MODS) $(filter-out \ $(patsubst %,%_tests,$(EUNIT_EBIN_MODS)),$(EUNIT_TEST_MODS)),'$(mod)') -eunit: test-build $(if $(IS_APP),,apps-eunit) +eunit: test-build $(if $(IS_APP),,apps-eunit) cover-data-dir $(gen_verbose) $(call erlang,$(call eunit.erl,[$(call comma_list,$(EUNIT_MODS))]),$(EUNIT_ERL_OPTS)) ifneq ($(ALL_APPS_DIRS),) @@ -6381,6 +6501,60 @@ apps-eunit: endif endif +# Copyright (c) 2015-2017, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +ifeq ($(filter proper,$(DEPS) $(TEST_DEPS)),proper) +.PHONY: proper + +# Targets. + +tests:: proper + +define proper_check.erl + code:add_pathsa(["$(call core_native_path,$(CURDIR)/ebin)", "$(call core_native_path,$(DEPS_DIR)/*/ebin)"]), + Module = fun(M) -> + [true] =:= lists:usort([ + case atom_to_list(F) of + "prop_" ++ _ -> + io:format("Testing ~p:~p/0~n", [M, F]), + proper:quickcheck(M:F(), nocolors); + _ -> + true + end + || {F, 0} <- M:module_info(exports)]) + end, + try + case $(1) of + all -> [true] =:= lists:usort([Module(M) || M <- [$(call comma_list,$(3))]]); + module -> Module($(2)); + function -> proper:quickcheck($(2), nocolors) + end + of + true -> halt(0); + _ -> halt(1) + catch error:undef -> + io:format("Undefined property or module?~n~p~n", [erlang:get_stacktrace()]), + halt(0) + end. +endef + +ifdef t +ifeq (,$(findstring :,$(t))) +proper: test-build + $(verbose) $(call erlang,$(call proper_check.erl,module,$(t))) +else +proper: test-build + $(verbose) echo Testing $(t)/0 + $(verbose) $(call erlang,$(call proper_check.erl,function,$(t)())) +endif +else +proper: test-build + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename $(wildcard ebin/*.beam)))))) + $(gen_verbose) $(call erlang,$(call proper_check.erl,all,undefined,$(MODULES))) +endif +endif + # Copyright (c) 2013-2016, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. @@ -6391,9 +6565,10 @@ endif RELX ?= $(ERLANG_MK_TMP)/relx RELX_CONFIG ?= $(CURDIR)/relx.config -RELX_URL ?= https://github.com/erlware/relx/releases/download/v3.19.0/relx +RELX_URL ?= https://github.com/erlware/relx/releases/download/v3.23.0/relx RELX_OPTS ?= RELX_OUTPUT_DIR ?= _rel +RELX_REL_EXT ?= RELX_TAR ?= 1 ifdef SFX @@ -6436,7 +6611,7 @@ distclean-relx-rel: # Run target. ifeq ($(wildcard $(RELX_CONFIG)),) -run: +run:: else define get_relx_release.erl @@ -6456,8 +6631,12 @@ RELX_REL := $(shell $(call erlang,$(get_relx_release.erl))) RELX_REL_NAME := $(word 1,$(RELX_REL)) RELX_REL_VSN := $(word 2,$(RELX_REL)) -run: all - $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_REL_NAME)/bin/$(RELX_REL_NAME) console +ifeq ($(PLATFORM),msys2) +RELX_REL_EXT := .cmd +endif + +run:: all + $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_REL_NAME)/bin/$(RELX_REL_NAME)$(RELX_REL_EXT) console help:: $(verbose) printf "%s\n" "" \ @@ -6492,7 +6671,7 @@ help:: $(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep)))) build-shell-deps: $(ALL_SHELL_DEPS_DIRS) - $(verbose) for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done + $(verbose) set -e; for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done shell: build-shell-deps $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) @@ -6522,7 +6701,10 @@ ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) tests:: triq define triq_check.erl - code:add_pathsa(["$(call core_native_path,$(CURDIR)/ebin)", "$(call core_native_path,$(DEPS_DIR)/*/ebin)"]), + code:add_pathsa([ + "$(call core_native_path,$(CURDIR)/ebin)", + "$(call core_native_path,$(DEPS_DIR)/*/ebin)", + "$(call core_native_path,$(TEST_DIR))"]), try case $(1) of all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); @@ -6533,7 +6715,7 @@ define triq_check.erl true -> halt(0); _ -> halt(1) catch error:undef -> - io:format("Undefined property or module~n"), + io:format("Undefined property or module?~n~p~n", [erlang:get_stacktrace()]), halt(0) end. endef @@ -6549,7 +6731,8 @@ triq: test-build endif else triq: test-build - $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename $(wildcard ebin/*.beam)))))) + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ + $(wildcard ebin/*.beam) $(call core_find,$(TEST_DIR)/,*.beam)))))) $(gen_verbose) $(call erlang,$(call triq_check.erl,all,undefined,$(MODULES))) endif endif @@ -6571,14 +6754,14 @@ endif XREFR ?= $(CURDIR)/xrefr export XREFR -XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/0.2.2/xrefr +XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/1.1.0/xrefr # Core targets. help:: - $(verbose) printf "%s\n" "" \ - "Xref targets:" \ - " xref Run Xrefr using $XREF_CONFIG as config file if defined" + $(verbose) printf '%s\n' '' \ + 'Xref targets:' \ + ' xref Run Xrefr using $$XREF_CONFIG as config file if defined' distclean:: distclean-xref @@ -6598,26 +6781,25 @@ distclean-xref: # Copyright (c) 2015, Viktor Söderqvist # This file is part of erlang.mk and subject to the terms of the ISC License. -COVER_REPORT_DIR = cover +COVER_REPORT_DIR ?= cover +COVER_DATA_DIR ?= $(CURDIR) # Hook in coverage to ct ifdef COVER ifdef CT_RUN -# All modules in 'ebin' -COVER_MODS = $(notdir $(basename $(call core_ls,ebin/*.beam))) - +ifneq ($(wildcard $(TEST_DIR)),) test-build:: $(TEST_DIR)/ct.cover.spec -$(TEST_DIR)/ct.cover.spec: - $(verbose) echo Cover mods: $(COVER_MODS) +$(TEST_DIR)/ct.cover.spec: cover-data-dir $(gen_verbose) printf "%s\n" \ - '{incl_mods,[$(subst $(space),$(comma),$(COVER_MODS))]}.' \ - '{export,"$(CURDIR)/ct.coverdata"}.' > $@ + "{incl_app, '$(PROJECT)', details}." \ + '{export,"$(abspath $(COVER_DATA_DIR))/ct.coverdata"}.' > $@ CT_RUN += -cover $(TEST_DIR)/ct.cover.spec endif endif +endif # Core targets @@ -6626,6 +6808,13 @@ ifneq ($(COVER_REPORT_DIR),) tests:: $(verbose) $(MAKE) --no-print-directory cover-report endif + +cover-data-dir: | $(COVER_DATA_DIR) + +$(COVER_DATA_DIR): + $(verbose) mkdir -p $(COVER_DATA_DIR) +else +cover-data-dir: endif clean:: coverdata-clean @@ -6639,7 +6828,7 @@ help:: "Cover targets:" \ " cover-report Generate a HTML coverage report from previously collected" \ " cover data." \ - " all.coverdata Merge {eunit,ct}.coverdata into one coverdata file." \ + " all.coverdata Merge all coverdata files into all.coverdata." \ "" \ "If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \ "target tests additionally generates a HTML coverage report from the combined" \ @@ -6648,17 +6837,20 @@ help:: # Plugin specific targets -COVERDATA = $(filter-out all.coverdata,$(wildcard *.coverdata)) +COVERDATA = $(filter-out $(COVER_DATA_DIR)/all.coverdata,$(wildcard $(COVER_DATA_DIR)/*.coverdata)) .PHONY: coverdata-clean coverdata-clean: - $(gen_verbose) rm -f *.coverdata ct.cover.spec + $(gen_verbose) rm -f $(COVER_DATA_DIR)/*.coverdata $(TEST_DIR)/ct.cover.spec # Merge all coverdata files into one. -all.coverdata: $(COVERDATA) - $(gen_verbose) $(ERL) -eval ' \ - $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) \ - cover:export("$@"), halt(0).' +define cover_export.erl + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) + cover:export("$(COVER_DATA_DIR)/$@"), halt(0). +endef + +all.coverdata: $(COVERDATA) cover-data-dir + $(gen_verbose) $(call erlang,$(cover_export.erl)) # These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to # empty if you want the coverdata files but not the HTML report. @@ -6668,6 +6860,7 @@ ifneq ($(COVER_REPORT_DIR),) cover-report-clean: $(gen_verbose) rm -rf $(COVER_REPORT_DIR) + $(if $(shell ls -A $(COVER_DATA_DIR)/),,$(verbose) rmdir $(COVER_DATA_DIR)) ifeq ($(COVERDATA),) cover-report: @@ -6676,7 +6869,7 @@ else # Modules which include eunit.hrl always contain one line without coverage # because eunit defines test/0 which is never called. We compensate for this. EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \ - grep -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ + grep -H -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ | sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq)) define cover_report.erl @@ -6711,7 +6904,7 @@ define cover_report.erl endef cover-report: - $(gen_verbose) mkdir -p $(COVER_REPORT_DIR) + $(verbose) mkdir -p $(COVER_REPORT_DIR) $(gen_verbose) $(call erlang,$(cover_report.erl)) endif @@ -6771,12 +6964,6 @@ endif DEP_PLUGINS ?= -define core_dep_plugin --include $(DEPS_DIR)/$(1) - -$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; -endef - $(foreach p,$(DEP_PLUGINS),\ $(eval $(if $(findstring /,$p),\ $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ @@ -6849,22 +7036,20 @@ ifeq ($(IS_APP)$(IS_DEP),) $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST) endif ifndef IS_APP - $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(verbose) set -e; for dep in $(ALL_APPS_DIRS) ; do \ $(MAKE) -C $$dep $@ \ IS_APP=1 \ - ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ - || exit $$?; \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST); \ done endif - $(verbose) for dep in $^ ; do \ + $(verbose) set -e; for dep in $^ ; do \ if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \ echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \ - if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk)$$" \ + if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk|.*ERLANG_MK_FILENAME.*)$$" \ $$dep/GNUmakefile $$dep/makefile $$dep/Makefile; then \ $(MAKE) -C $$dep fetch-deps \ IS_DEP=1 \ - ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ - || exit $$?; \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST); \ fi \ fi \ done diff --git a/examples/hello_sdl/hello_sdl.erl b/examples/hello_sdl/hello_sdl.erl index 4e06baf..54e0f36 100644 --- a/examples/hello_sdl/hello_sdl.erl +++ b/examples/hello_sdl/hello_sdl.erl @@ -4,7 +4,7 @@ -export([run/0]). run() -> - spawn_opt(fun init/0, [{scheduler, 0}]). + spawn(fun init/0). init() -> ok = sdl:start([video]), diff --git a/src/esdl2.erl b/src/esdl2.erl index 7bacb71..0b1b456 100644 --- a/src/esdl2.erl +++ b/src/esdl2.erl @@ -64,6 +64,17 @@ -export([start_text_input/0]). -export([stop_text_input/0]). +%% sdl_mouse +-export([capture_mouse/1]). +-export([get_global_mouse_state/0]). +-export([get_mouse_focus/0]). +-export([get_mouse_state/0]). +-export([get_relative_mouse_mode/0]). +-export([get_relative_mouse_state/0]). +-export([set_relative_mouse_mode/1]). +-export([warp_mouse_global/2]). +-export([warp_mouse_in_window/3]). + %% sdl_power -export([get_power_info/0]). @@ -269,6 +280,35 @@ start_text_input() -> stop_text_input() -> erlang:nif_error({not_loaded, ?MODULE}). +%% sdl_mouse + +capture_mouse(_) -> + erlang:nif_error({not_loaded, ?MODULE}). + +get_global_mouse_state() -> + erlang:nif_error({not_loaded, ?MODULE}). + +get_mouse_focus() -> + erlang:nif_error({not_loaded, ?MODULE}). + +get_mouse_state() -> + erlang:nif_error({not_loaded, ?MODULE}). + +get_relative_mouse_mode() -> + erlang:nif_error({not_loaded, ?MODULE}). + +get_relative_mouse_state() -> + erlang:nif_error({not_loaded, ?MODULE}). + +set_relative_mouse_mode(_) -> + erlang:nif_error({not_loaded, ?MODULE}). + +warp_mouse_global(_, _) -> + erlang:nif_error({not_loaded, ?MODULE}). + +warp_mouse_in_window(_, _, _) -> + erlang:nif_error({not_loaded, ?MODULE}). + %% sdl_power get_power_info() -> diff --git a/src/sdl_mouse.erl b/src/sdl_mouse.erl new file mode 100644 index 0000000..d6c3815 --- /dev/null +++ b/src/sdl_mouse.erl @@ -0,0 +1,72 @@ +%% Copyright (c) 2017, Loïc Hoguin +%% +%% 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. +%% +%% THE 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. + +-module(sdl_mouse). + +-export([capture/1]). +-export([get_focused_window/0]). +-export([get_global_state/0]). +-export([get_relative_mode/0]). +-export([get_relative_state/0]). +-export([get_state/0]). +-export([set_relative_mode/1]). +-export([warp/2]). +-export([warp/3]). + +-spec capture(boolean()) -> ok | sdl:error(). +capture(Bool) -> + esdl2:capture_mouse(Bool), + receive {'_nif_thread_ret_', Ret} -> Ret end. + +-spec get_focused_window() -> sdl_window:window() | undefined. +get_focused_window() -> + esdl2:get_mouse_focus(), + receive {'_nif_thread_ret_', Ret} -> Ret end. + +-spec get_global_state() + -> {integer(), integer(), [left | middle | right | x1 | x2]}. +get_global_state() -> + esdl2:get_global_mouse_state(), + receive {'_nif_thread_ret_', Ret} -> Ret end. + +-spec get_relative_mode() -> boolean(). +get_relative_mode() -> + esdl2:get_relative_mouse_mode(), + receive {'_nif_thread_ret_', Ret} -> Ret end. + +-spec get_relative_state() + -> {integer(), integer(), [left | middle | right | x1 | x2]}. +get_relative_state() -> + esdl2:get_relative_mouse_state(), + receive {'_nif_thread_ret_', Ret} -> Ret end. + +-spec get_state() + -> {integer(), integer(), [left | middle | right | x1 | x2]}. +get_state() -> + esdl2:get_mouse_state(), + receive {'_nif_thread_ret_', Ret} -> Ret end. + +-spec set_relative_mode(boolean()) -> ok | sdl:error(). +set_relative_mode(Bool) -> + esdl2:set_relative_mouse_mode(Bool), + receive {'_nif_thread_ret_', Ret} -> Ret end. + +-spec warp(integer(), integer()) -> ok | sdl:error(). +warp(X, Y) -> + esdl2:warp_mouse_global(X, Y), + receive {'_nif_thread_ret_', Ret} -> Ret end. + +-spec warp(sdl_window:window(), integer(), integer()) -> ok. +warp(Window, X, Y) -> + esdl2:warp_mouse_in_window(Window, X, Y). -- cgit v1.2.3