├── .gitignore ├── LICENSE ├── README.md ├── co.c ├── co.h ├── example.c ├── example_part.c ├── example_part.h ├── makefile └── scheme.mk /.gitignore: -------------------------------------------------------------------------------- 1 | *.[oda] 2 | *.~ 3 | *.swp 4 | *.gcno 5 | *.out 6 | tags 7 | gh-pages 8 | *.tests 9 | *.sancov 10 | *.profraw 11 | *.profdata 12 | *.pyc 13 | .dep.mk 14 | example 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2019, Liu Liu 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | https://liuliu.me/eyes/a-more-natural-stackless-coroutine-in-c-maintains-local-variables/ 2 | -------------------------------------------------------------------------------- /co.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "co.h" 3 | 4 | static void _co_prepend_task(co_scheduler_t* const scheduler, co_routine_t* const task) 5 | { 6 | if (scheduler->head) 7 | { 8 | scheduler->head->prev = task; 9 | task->next = scheduler->head; 10 | } else { 11 | scheduler->tail = task; 12 | task->next = 0; 13 | } 14 | scheduler->head = task; 15 | task->prev = 0; 16 | } 17 | 18 | static void _co_append_task(co_scheduler_t* const scheduler, co_routine_t* const task) 19 | { 20 | if (scheduler->tail) 21 | { 22 | scheduler->tail->next = task; 23 | task->prev = scheduler->tail; 24 | } else { 25 | scheduler->head = task; 26 | task->prev = 0; 27 | } 28 | scheduler->tail = task; 29 | task->next = 0; 30 | } 31 | 32 | static void _co_delete_task(co_scheduler_t* const scheduler, co_routine_t* const task) 33 | { 34 | if (task->prev) 35 | task->prev->next = task->next; 36 | else 37 | scheduler->head = task->next; 38 | if (task->next) 39 | task->next->prev = task->prev; 40 | else 41 | scheduler->tail = task->prev; 42 | 43 | } 44 | 45 | static co_routine_t* _co_done(co_routine_t* const task) 46 | { 47 | if (task->notify_any) 48 | { 49 | co_routine_t* const notify_any = task->notify_any; 50 | task->notify_any = 0; 51 | int i; 52 | const int other_size = notify_any->other_size; 53 | notify_any->other_size = 0; 54 | co_routine_t* const* const others = notify_any->others; 55 | for (i = 0; i < other_size; i++) 56 | if (others[i] != task) 57 | { 58 | assert(others[i]->notify_any == notify_any); 59 | others[i]->notify_any = 0; 60 | } 61 | return notify_any; 62 | } 63 | return 0; 64 | } 65 | 66 | void _co_resume(co_routine_t* const self, co_routine_t* const task) 67 | { 68 | assert(!task->done); 69 | task->scheduler = self->scheduler; 70 | task->caller = self; 71 | self->callee = task; 72 | } 73 | 74 | void _co_apply(co_routine_t* const self, co_routine_t* const task) 75 | { 76 | assert(!task->done); 77 | task->scheduler = self->scheduler; 78 | self->callee = task; 79 | task->caller = 0; // Doesn't automatic resume from this task. 80 | _co_await_any(self, &task, 1); 81 | } 82 | 83 | int _co_await_any(co_routine_t* const self, co_routine_t* const* const tasks, const int task_size) 84 | { 85 | assert(task_size > 0); 86 | if (task_size == 1) // Special casing this, no need to add to others list, which has life-cycle requirement for this list. 87 | { 88 | self->others = 0; 89 | self->other_size = 0; 90 | if (tasks[0]->done) 91 | return 1; 92 | tasks[0]->notify_any = self; 93 | return 0; 94 | } 95 | self->others = tasks; 96 | self->other_size = task_size; 97 | int i; 98 | int flag = 0; 99 | for (i = 0; !flag && i < task_size; i++) 100 | { 101 | flag = tasks[i]->done; 102 | assert(tasks[i]->notify_any == 0); 103 | tasks[i]->notify_any = self; 104 | } 105 | if (flag) 106 | { 107 | for (i = 0; i < task_size; i++) 108 | tasks[i]->notify_any = 0; 109 | return 1; 110 | } 111 | return 0; 112 | } 113 | 114 | void co_free(co_routine_t* const task) 115 | { 116 | free(task); 117 | } 118 | 119 | int co_is_done(const co_routine_t* const task) 120 | { 121 | return task->done; 122 | } 123 | 124 | static void _co_main(co_scheduler_t* const scheduler) 125 | { 126 | for (;;) 127 | { 128 | if (scheduler->head == 0) 129 | break; 130 | co_routine_t* task = scheduler->head; 131 | _co_delete_task(scheduler, task); 132 | while (task) { 133 | const co_state_t state = task->fn(task, task + 1); 134 | task->line = state.line; 135 | task->done = state.done; 136 | if (task->callee) 137 | task = task->callee; 138 | else { 139 | co_routine_t* const prev_task = task; 140 | task = task->caller; 141 | prev_task->caller = 0; 142 | if (prev_task->done) 143 | { 144 | co_routine_t* const notify_any = _co_done(prev_task); 145 | if (prev_task->root) // Free the task scheduled from co_schedule. 146 | co_free(prev_task); 147 | if (notify_any) 148 | { 149 | if (!task) 150 | task = notify_any; 151 | else 152 | _co_prepend_task(scheduler, notify_any); 153 | } 154 | } 155 | } 156 | } 157 | } 158 | } 159 | 160 | co_scheduler_t* co_scheduler_new(void) 161 | { 162 | co_scheduler_t* const scheduler = calloc(1, sizeof(co_scheduler_t)); 163 | return scheduler; 164 | } 165 | 166 | void co_scheduler_free(co_scheduler_t* const scheduler) 167 | { 168 | free(scheduler); 169 | } 170 | 171 | void co_schedule(co_scheduler_t* const scheduler, co_routine_t* const task) 172 | { 173 | task->scheduler = scheduler; 174 | task->root = 1; // If this is the root, we will free it ourselves. 175 | _co_append_task(scheduler, task); 176 | if (scheduler->active) 177 | return; 178 | _co_main(scheduler); 179 | } 180 | -------------------------------------------------------------------------------- /co.h: -------------------------------------------------------------------------------- 1 | #ifndef GUARD_co_h 2 | #define GUARD_co_h 3 | 4 | #include 5 | #include 6 | 7 | typedef struct co_routine_s co_routine_t; 8 | 9 | typedef struct { 10 | int active; 11 | co_routine_t* head; 12 | co_routine_t* tail; 13 | } co_scheduler_t; 14 | 15 | typedef struct { 16 | int line; 17 | int done; 18 | } co_state_t; 19 | 20 | typedef co_state_t(*co_task_f)(struct co_routine_s* const self, void* const privates); 21 | 22 | struct co_routine_s { 23 | int line; 24 | int done; 25 | int root; 26 | int other_size; 27 | co_scheduler_t* scheduler; 28 | co_routine_t* prev; 29 | co_routine_t* next; 30 | co_routine_t* notify_any; 31 | co_routine_t* const* others; 32 | co_routine_t* callee; 33 | co_routine_t* caller; 34 | co_task_f fn; 35 | }; 36 | 37 | #define co_params_0(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,_51,_52,_53,_54,_55,_56,_57,_58,_59,_60,_61,_62,_63,...) _0;_1;_2;_3;_4;_5;_6;_7;_8;_9;_10;_11;_12;_13;_14;_15;_16;_17;_18;_19;_20;_21;_22;_23;_24;_25;_26;_27;_28;_29;_30;_31;_32;_33;_34;_35;_36;_37;_38;_39;_40;_41;_42;_43;_44;_45;_46;_47;_48;_49;_50;_51;_52;_53;_54;_55;_56;_57;_58;_59;_60;_61;_62;_63; 38 | 39 | #define co_params(...) co_params_0(__VA_ARGS__,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,) 40 | 41 | #define co_escape(...) __VA_ARGS__ 42 | 43 | #define co_private(...) __VA_ARGS__ 44 | 45 | #define co_decl_1(_rettype, _func, _param) \ 46 | co_state_t _func(co_routine_t* const _self_, void* const _privates_); \ 47 | struct _func ## _param_s { \ 48 | _rettype _co_ret; \ 49 | struct { \ 50 | co_params _param \ 51 | } _co_params; \ 52 | }; \ 53 | size_t _func ## _stack_size(void); 54 | 55 | #define co_decl_0(_func, _param) \ 56 | co_state_t _func(co_routine_t* const _self, void* const _privates_); \ 57 | struct _func ## _param_s { \ 58 | struct { \ 59 | co_params _param \ 60 | } _co_params; \ 61 | }; \ 62 | size_t _func ## _stack_size(void); 63 | 64 | #define co_decl_sel(_0, _1, _2, ...) _2 65 | 66 | #define co_decl(_func_or_rettype, _param_or_func, ...) co_decl_sel(_0, ## __VA_ARGS__, co_decl_1, co_decl_0)(_func_or_rettype, _param_or_func, ## __VA_ARGS__) 67 | 68 | #define co_task_1(_rettype, _func, _param, _private) \ 69 | struct _func ## _private_s { \ 70 | struct _func ## _param_s _co_params; \ 71 | co_ ## _private \ 72 | }; \ 73 | size_t _func ## _stack_size(void) { return sizeof(struct _func ## _private_s); } \ 74 | co_state_t _func(co_routine_t* const _self_, void* const _privates_) \ 75 | { \ 76 | struct _private_s { \ 77 | struct _func ## _param_s _co_params; \ 78 | co_ ## _private \ 79 | }; \ 80 | switch (_self_->line) { \ 81 | case 0: 82 | 83 | #define co_task_0(_func, _param, _private) \ 84 | struct _func ## _private_s { \ 85 | struct _func ## _param_s _co_params; \ 86 | co_ ## _private \ 87 | }; \ 88 | size_t _func ## _stack_size(void) { return sizeof(struct _func ## _private_s); } \ 89 | co_state_t _func(co_routine_t* const _self_, void* const _privates_) \ 90 | { \ 91 | struct _private_s { \ 92 | struct _func ## _param_s _co_params; \ 93 | co_ ## _private \ 94 | }; \ 95 | switch (_self_->line) { \ 96 | case 0: 97 | 98 | #define co_task_sel(_0, _1, _2, ...) _2 99 | 100 | #define co_task(_func_or_rettype, _param_or_func, _private_or_param, ...) co_task_sel(_0, ## __VA_ARGS__, co_task_1, co_task_0)(_func_or_rettype, _param_or_func, _private_or_param, ## __VA_ARGS__) 101 | 102 | #define co_decl_task_1(_rettype, _func, _param, _private) \ 103 | co_decl_1(_rettype, _func, _param) \ 104 | co_task_1(_rettype, _func, _param, _private) 105 | 106 | #define co_decl_task_0(_func, _param, _private) \ 107 | co_decl_0(_func, _param) \ 108 | co_task_0(_func, _param, _private) 109 | 110 | #define co_decl_task_sel(_0, _1, _2, ...) _2 111 | 112 | #define co_decl_task(_func_or_rettype, _param_or_func, _private_or_param, ...) co_decl_task_sel(_0, ## __VA_ARGS__, co_decl_task_1, co_decl_task_0)(_func_or_rettype, _param_or_func, _private_or_param, ## __VA_ARGS__) 113 | 114 | #define co_end() default: return (co_state_t){ __LINE__, 1 }; } } 115 | 116 | #define CO_P(_x) (((struct _private_s*)(_privates_))->_co_params._co_params._x) 117 | #define CO_V(_x) (((struct _private_s*)(_privates_))->_x) 118 | 119 | #define co_self() (_self_) 120 | 121 | #define co_yield(_val) do { ((struct _private_s*)(_privates_))->_co_params._co_ret = _val; return (co_state_t){ __LINE__, 0 }; case __LINE__: ; } while (0) 122 | 123 | #define co_return_1(_val) do { ((struct _private_s*)(_privates_))->_co_params._co_ret = _val; return (co_state_t){ __LINE__, 1 }; } while (0) 124 | 125 | #define co_return_0() do { return (co_state_t){ __LINE__, 1 }; } while (0) 126 | 127 | #define co_return_sel(_0, _1, _2, ...) _2 128 | 129 | #define co_return(...) co_return_sel(_0, ## __VA_ARGS__, co_return_1, co_return_0)(__VA_ARGS__) 130 | 131 | #define co_init(_task, _func, _param) do { \ 132 | struct _func ## _param_s params = { \ 133 | ._co_params = { co_escape _param } \ 134 | }; \ 135 | _task->fn = _func; \ 136 | _task->line = 0; \ 137 | _task->done = 0; \ 138 | _task->root = 0; \ 139 | _task->other_size = 0; \ 140 | _task->notify_any = 0; \ 141 | _task->others = 0; \ 142 | _task->caller = 0; \ 143 | _task->callee = 0; \ 144 | if (sizeof(params) > 0) \ 145 | memcpy(_task + 1, ¶ms, sizeof(params)); \ 146 | } while (0) 147 | 148 | #define co_size(_func) (sizeof(co_routine_t) + _func ## _stack_size()) 149 | 150 | #define co_new(_func, _param) ({ \ 151 | co_routine_t* const task = malloc(co_size(_func)); \ 152 | co_init(task, _func, _param); \ 153 | task; \ 154 | }) 155 | 156 | #define co_retval_2(_task, _rettype) *(_rettype*)(_task + 1) 157 | 158 | #define co_retval_0() ((struct _private_s*)(_privates_))->_co_params._co_ret 159 | 160 | #define co_retval_sel(_0, _1, _2, _3, ...) _3 161 | 162 | #define co_retval(...) co_retval_sel(_0, ## __VA_ARGS__, co_retval_2, co_retval_1, co_retval_0)(__VA_ARGS__) 163 | 164 | #define co_await_any(_tasks, _task_size) do { if (!_co_await_any(_self_, _tasks, _task_size)) { return (co_state_t){ __LINE__, 0 }; } case __LINE__: ; } while (0) 165 | 166 | #define co_await_1(_task, _val) do { \ 167 | co_await_any(&(_task), 1); \ 168 | _val = co_retval(_task, typeof(_val)); \ 169 | } while (0) 170 | 171 | #define co_await_0(_task) \ 172 | co_await_any(&(_task), 1) 173 | 174 | #define co_await_sel(_0, _1, _2, ...) _2 175 | 176 | #define co_await(_task, ...) co_await_sel(_0, ## __VA_ARGS__, co_await_1, co_await_0)(_task, ## __VA_ARGS__) 177 | 178 | #define co_apply_1(_func, _param, _val) do { \ 179 | _self_->callee = co_new(_func, _param); \ 180 | _co_apply(_self_, _self_->callee); \ 181 | return (co_state_t){ __LINE__, 0 }; \ 182 | case __LINE__: \ 183 | _val = co_retval(&(_self_->callee), typeof(_val)); \ 184 | co_free(_self_->callee); \ 185 | _self_->callee = 0; \ 186 | } while (0) 187 | 188 | #define co_apply_0(_func, _param) do { \ 189 | _self_->callee = co_new(_func, _param); \ 190 | _co_apply(_self_, _self_->callee); \ 191 | return (co_state_t){ __LINE__, 0 }; \ 192 | case __LINE__: \ 193 | co_free(_self_->callee); \ 194 | _self_->callee = 0; \ 195 | } while (0) 196 | 197 | #define co_apply_sel(_0, _1, _2, ...) _2 198 | 199 | #define co_apply(_func, _param, ...) co_apply_sel(_0, ## __VA_ARGS__, co_apply_1, co_apply_0)(_func, _param, ## __VA_ARGS__) 200 | 201 | #define co_resume_1(_task, _val) do { \ 202 | _co_resume(_self_, _task); \ 203 | return (co_state_t){ __LINE__, 0 }; \ 204 | case __LINE__: \ 205 | _self_->callee = 0; \ 206 | _val = co_retval(_task, typeof(_val)); \ 207 | } while (0) 208 | 209 | #define co_resume_0(_task) do { \ 210 | _co_resume(_self_, _task); \ 211 | return (co_state_t){ __LINE__, 0 }; \ 212 | case __LINE__: \ 213 | _self_->callee = 0; \ 214 | } while (0) 215 | 216 | #define co_resume_sel(_0, _1, _2, ...) _2 217 | 218 | #define co_resume(_task, ...) co_resume_sel(_0, ## __VA_ARGS__, co_resume_1, co_resume_0)(_task, ## __VA_ARGS__) 219 | 220 | void _co_apply(co_routine_t* const self, co_routine_t* const task); 221 | void _co_resume(co_routine_t* const self, co_routine_t* const task); 222 | int _co_await_any(co_routine_t* const self, co_routine_t* const* const tasks, const int task_size); 223 | 224 | void co_free(co_routine_t* const task); 225 | int co_is_done(const co_routine_t* const task); 226 | co_scheduler_t* co_scheduler_new(void); 227 | void co_scheduler_free(co_scheduler_t* const scheduler); 228 | void co_schedule(co_scheduler_t* const scheduler, co_routine_t* const task); 229 | 230 | #endif 231 | -------------------------------------------------------------------------------- /example.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "co.h" 4 | 5 | #include "example_part.h" 6 | 7 | typedef struct { 8 | int a; 9 | int b; 10 | } ab_t; 11 | 12 | static co_decl_task(ab_t, _coroutine_a, (const int a, const int b), private( 13 | int i; 14 | )) { 15 | printf("param a %d\n", CO_P(a)); 16 | printf("param b %d\n", CO_P(b)); 17 | CO_V(i) = 2; 18 | printf("%d\n", CO_V(i)); 19 | co_yield((ab_t){ 20 | .a = CO_V(i) 21 | }); 22 | CO_V(i) += 1; 23 | printf("param b %d\n", CO_P(b)); 24 | printf("%d\n", CO_V(i)); 25 | co_yield((ab_t){ 26 | .a = CO_V(i) 27 | }); 28 | co_return((ab_t){ 29 | .a = 10 30 | }); 31 | } co_end() 32 | 33 | static co_decl_task(int, _coroutine_b, (), private( 34 | co_routine_t* task_a; 35 | co_routine_t* task_c; 36 | ab_t a0; 37 | ab_t a1; 38 | ab_t a2; 39 | )) { 40 | CO_V(task_a) = co_new(_coroutine_a, (12, 10)); 41 | co_resume(CO_V(task_a), CO_V(a0)); 42 | CO_V(task_c) = malloc(co_size(_coroutine_c)); 43 | co_init(CO_V(task_c), _coroutine_c, (CO_V(task_a))); 44 | co_resume(CO_V(task_c)); 45 | co_resume(CO_V(task_a), CO_V(a1)); 46 | co_resume(CO_V(task_a), CO_V(a2)); 47 | printf("returned value %d %d %d\n", CO_V(a0).a, CO_V(a1).a, CO_V(a2).a); 48 | co_free(CO_V(task_a)); 49 | co_await(CO_V(task_c)); 50 | free(CO_V(task_c)); 51 | } co_end() 52 | 53 | int main(void) 54 | { 55 | co_scheduler_t* scheduler = co_scheduler_new(); 56 | co_routine_t* const task = co_new(_coroutine_b, ()); 57 | co_schedule(scheduler, task); 58 | co_scheduler_free(scheduler); 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /example_part.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "example_part.h" 4 | 5 | static co_decl(_coroutine_d, ()); 6 | 7 | co_task(_coroutine_c, (co_routine_t* const other), private( 8 | )) { 9 | printf("wait for task %p\n", CO_P(other)); 10 | co_await(CO_P(other)); 11 | printf("resumed because task a is done\n"); 12 | co_apply(_coroutine_d, ()); 13 | printf("resumed because task d is done\n"); 14 | co_return(); 15 | } co_end() 16 | 17 | co_task(_coroutine_d, (), private( 18 | )) { 19 | printf("this is coroutine d\n"); 20 | } co_end() 21 | -------------------------------------------------------------------------------- /example_part.h: -------------------------------------------------------------------------------- 1 | #ifndef GUARD_example_part_h 2 | #define GUARD_example_part_h 3 | 4 | #include "co.h" 5 | 6 | co_decl(_coroutine_c, (co_routine_t* const other)); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | LDFLAGS := -lm 2 | CFLAGS := -O3 -ffast-math -Wall -I"." $(CFLAGS) 3 | 4 | SRCS := co.c example_part.c 5 | 6 | TARGETS = example 7 | 8 | SRC_OBJS := $(patsubst %.c,%.o,$(SRCS)) 9 | 10 | # Make nnc/libnnc.o a phony target therefore it will be triggered every time. 11 | .PHONY: release all lib clean dep 12 | 13 | release: all 14 | 15 | include scheme.mk 16 | 17 | all: $(TARGETS) 18 | 19 | $(TARGETS): %: %.o $(SRC_OBJS) 20 | $(CC) -o $@ $< co.o example_part.o $(LDFLAGS) 21 | 22 | clean: 23 | rm -f $(TARGETS) *.o 24 | 25 | %.o: %.c 26 | $(CC) $< -o $@ -c $(CFLAGS) 27 | 28 | dep: .dep.mk 29 | .dep.mk: $(SRCS) 30 | echo '' > .dep.mk 31 | for SRC in $(patsubst %.cu,,$^) ; do \ 32 | $(CC) $(CFLAGS) -MM $$SRC | sed -e 's/^.*\://g' | (echo "$${SRC%%.*}.o: \\" && cat) >> .dep.mk ; \ 33 | done 34 | 35 | -include .dep.mk 36 | -------------------------------------------------------------------------------- /scheme.mk: -------------------------------------------------------------------------------- 1 | .PHONY: debug undef asan 2 | 3 | # Debug Scheme 4 | 5 | DEBUG ?= 0 6 | ifeq ($(DEBUG), 1) 7 | CFLAGS += -g -fno-omit-frame-pointer -O0 8 | LDFLAGS += -g -fno-omit-frame-pointer -O0 9 | endif 10 | 11 | debug: CFLAGS += -g -fno-omit-frame-pointer -O0 12 | debug: LDFLAGS += -g -fno-omit-frame-pointer -O0 13 | debug: export DEBUG = 1 14 | debug: all 15 | 16 | # Asan Scheme 17 | 18 | ASAN ?= 0 19 | ifeq ($(ASAN), 1) 20 | CFLAGS += -g -fno-omit-frame-pointer -fsanitize=address 21 | LDFLAGS += -g -fno-omit-frame-pointer -fsanitize=address 22 | endif 23 | 24 | asan: CFLAGS += -g -fno-omit-frame-pointer -fsanitize=address 25 | asan: LDFLAGS += -g -fno-omit-frame-pointer -fsanitize=address 26 | asan: export ASAN = 1 27 | asan: all 28 | 29 | # Undefined Scheme 30 | 31 | UNDEF ?= 0 32 | ifeq ($(UNDEF), 1) 33 | CFLAGS += -g -fno-omit-frame-pointer -O0 -fsanitize=address -fsanitize=undefined 34 | LDFLAGS += -g -fno-omit-frame-pointer -O0 -fsanitize=address -fsanitize=undefined 35 | endif 36 | 37 | undef: CFLAGS += -g -fno-omit-frame-pointer -O0 -fsanitize=address -fsanitize=undefined 38 | undef: LDFLAGS += -g -fno-omit-frame-pointer -O0 -fsanitize=address -fsanitize=undefined 39 | undef: export UNDEF = 1 40 | undef: all 41 | 42 | --------------------------------------------------------------------------------