diff --git a/.travis.yml b/.travis.yml index 7f4b815388..2a7b444aa8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,6 +18,7 @@ install: - sudo apt-get install gcc-msp430 - sudo apt-get install pcregrep libpcre3 - sudo apt-get install qemu-system-x86 python3 + - sudo apt-get install g++-multilib script: - ./dist/tools/compile_test/compile_test.py diff --git a/Makefile.base b/Makefile.base index 446ef1609c..f9cf7bbf30 100644 --- a/Makefile.base +++ b/Makefile.base @@ -30,8 +30,19 @@ ASMOBJ += $(ASSMSRC:%.S=$(BINDIR)$(MODULE)/%.o) ifeq ($(strip $(SRC)),) SRC = $(wildcard *.c) endif -OBJ = $(SRC:%.c=$(BINDIR)$(MODULE)/%.o) + +ifeq ($(strip $(SRCXX)),) + SRCXX = $(wildcard *.cpp) +endif + +OBJC = $(SRC:%.c=$(BINDIR)$(MODULE)/%.o) +OBJCXX = $(SRCXX:%.cpp=$(BINDIR)$(MODULE)/%.o) + +OBJ = $(OBJC) +OBJ += $(OBJCXX) + DEP = $(SRC:%.c=$(BINDIR)$(MODULE)/%.d) +DEP += $(SRCXX:%.cpp=$(BINDIR)$(MODULE)/%.d) $(BINDIR)$(MODULE).a: $(OBJ) $(ASMOBJ) ${DIRS:%=ALL--%} @mkdir -p $(BINDIR)$(MODULE) @@ -46,6 +57,10 @@ $(BINDIR)$(MODULE)/%.o: %.c @mkdir -p $(BINDIR)$(MODULE) $(AD)$(CC) $(CFLAGS) $(INCLUDES) -MD -MP -c -o $(BINDIR)$(MODULE)/$*.o $(abspath $*.c) +$(BINDIR)$(MODULE)/%.o: %.cpp + @mkdir -p $(BINDIR)$(MODULE) + $(AD)$(CXX) $(filter-out $(CXXUWFLAGS), $(CFLAGS)) $(CXXEXFLAGS) $(INCLUDES) -MD -MP -c -o $(BINDIR)$(MODULE)/$*.o $(abspath $*.cpp) + $(BINDIR)$(MODULE)/%.o: %.s @mkdir -p $(BINDIR)$(MODULE) $(AD)$(AS) $(ASFLAGS) $*.s -o $(BINDIR)$(MODULE)/$*.o diff --git a/Makefile.cflags b/Makefile.cflags index d1478e5dc0..6bf285d051 100644 --- a/Makefile.cflags +++ b/Makefile.cflags @@ -29,3 +29,6 @@ ifeq ($(shell $(CC) -Wstrict-prototypes -Werror=strict-prototypes -Wold-style-de # duplicated parameters don't hurt CFLAGS += -Wstrict-prototypes -Werror=strict-prototypes -Wold-style-definition -Werror=old-style-definition endif + +# Unwanted flags for c++ +CXXUWFLAGS += -std=gnu99 -std=c99 -Wstrict-prototypes -Wold-style-definition diff --git a/Makefile.include b/Makefile.include index 78285a6ed8..3bfb9865ad 100644 --- a/Makefile.include +++ b/Makefile.include @@ -90,14 +90,19 @@ BASELIBS += $(USEPKG:%=${BINDIR}%.a) export ELFFILE ?= $(BINDIR)$(APPLICATION).elf export HEXFILE ?= $(ELFFILE:.elf=.hex) +# variables used to complie and link c++ +export CPPMIX ?= $(if $(wildcard *.cpp),1,) +export CXXUWFLAGS +export CXXEXFLAGS + ## make script for your application. Build RIOT-base here! all: ..build-message $(USEPKG:%=${BINDIR}%.a) $(APPDEPS) $(AD)DIRS="$(DIRS)" "$(MAKE)" -C $(CURDIR) -f $(RIOTBASE)/Makefile.application ifeq (,$(RIOTNOLINK)) ifeq ($(BUILDOSXNATIVE),1) - $(AD)$(LINK) $(UNDEF) -o $(ELFFILE) $(BASELIBS) $(LINKFLAGS) -Wl,-no_pie + $(AD)$(if $(CPPMIX),$(CXX),$(LINK)) $(UNDEF) -o $(ELFFILE) $(BASELIBS) $(LINKFLAGS) -Wl,-no_pie else - $(AD)$(LINK) $(UNDEF) -o $(ELFFILE) -Wl,--start-group $(BASELIBS) -lm -Wl,--end-group -Wl,-Map=$(BINDIR)$(APPLICATION).map $(LINKFLAGS) + $(AD)$(if $(CPPMIX),$(CXX),$(LINK)) $(UNDEF) -o $(ELFFILE) -Wl,--start-group $(BASELIBS) -lm -Wl,--end-group -Wl,-Map=$(BINDIR)$(APPLICATION).map $(LINKFLAGS) endif $(AD)$(SIZE) $(ELFFILE) $(AD)$(OBJCOPY) $(OFLAGS) $(ELFFILE) $(HEXFILE) diff --git a/boards/native/Makefile.include b/boards/native/Makefile.include index cd76950f1a..6b5a8ccc77 100644 --- a/boards/native/Makefile.include +++ b/boards/native/Makefile.include @@ -10,6 +10,7 @@ export ELF = $(BINDIR)$(APPLICATION).elf # toolchain: export PREFIX = export CC ?= $(PREFIX)gcc +export CXX ?= $(PREFIX)g++ export AR ?= $(PREFIX)ar export AS ?= $(PREFIX)as export LINK ?= $(PREFIX)gcc @@ -31,6 +32,10 @@ export CFLAGS += -DCOMPAT_32BIT -L/usr/lib32 -B/usr/lib32 endif endif +# unwanted (CXXUWFLAGS) and extra (CXXEXFLAGS) flags for c++ +export CXXUWFLAGS += +export CXXEXFLAGS += + export LINKFLAGS += -m32 ifeq ($(shell uname -s),FreeBSD) ifeq ($(shell uname -m),amd64) diff --git a/examples/riot_and_cpp/Makefile b/examples/riot_and_cpp/Makefile new file mode 100644 index 0000000000..d6eb0131b9 --- /dev/null +++ b/examples/riot_and_cpp/Makefile @@ -0,0 +1,42 @@ +# name of your application +export APPLICATION = riot_and_cpp + +# If no BOARD is found in the environment, use this default: +export BOARD ?= native + +# This has to be the absolute path to the RIOT base directory: +export RIOTBASE ?= $(CURDIR)/../.. + +# Uncomment these lines if you want to use platform support from external +# repositories: +#export RIOTCPU ?= $(CURDIR)/../../../thirdparty_cpu +#export RIOTBOARD ?= $(CURDIR)/../../../thirdparty_boards + +# Uncomment this to enable scheduler statistics for ps: +#CFLAGS += -DSCHEDSTATISTICS + +# If you want to use native with valgrind, you should recompile native +# with the target all-valgrind instead of all: +# make -B clean all-valgrind + +# Uncomment this to enable code in RIOT that does safety checking +# which is not needed in a production environment but helps in the +# development process: +#CFLAGS += -DDEVELHELP + +# Change this to 0 show compiler invocation lines by default: +export QUIET ?= 1 + +# Blacklist boards +BOARD_BLACKLIST := arduino-due avsextrem chronos mbed_lpc1768 msb-430h msba2 redbee-econotag telosb wsn430-v1_3b wsn430-v1_4 msb-430 pttu udoo qemu-i386 z1 +# This example only works with native for now. +# msb430-based boards: msp430-g++ is not provided in mspgcc. +# (People who want use c++ can build c++ compiler from source, or get binaries from Energia http://energia.nu/) +# msba2: some changes should be applied to successfully compile c++. (_kill_r, _kill, __dso_handle) +# others: untested. + +# If you want to add some extra flags when compile c++ files, add these flags +# to CXXEXFLAGS variable +CXXEXFLAGS += + +include $(RIOTBASE)/Makefile.include diff --git a/examples/riot_and_cpp/README.md b/examples/riot_and_cpp/README.md new file mode 100644 index 0000000000..59e9ada9ca --- /dev/null +++ b/examples/riot_and_cpp/README.md @@ -0,0 +1,7 @@ +Using C++ and C in a program with RIOT +====================================== +This project demonstrates how user can use both C++ and C in their application with RIOT. + +Makefile Options +---------------- +* CXXEXFLAGS : user's extra flags used to build c++ files should be defined here (e.g -std=gnu++11). diff --git a/examples/riot_and_cpp/c_functions.c b/examples/riot_and_cpp/c_functions.c new file mode 100644 index 0000000000..df1bc4e48e --- /dev/null +++ b/examples/riot_and_cpp/c_functions.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2014 Ho Chi Minh city University of Technology (HCMUT) + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup examples + * @{ + * + * @file c_functions.c + * @brief Some functions implementaion in C. + * + * @author DangNhat Pham-Huu <51002279@hcmut.edu.vn> + * + * @} + */ + +#include "c_functions.h" + +#define IS_LEAP_YEAR(year) ((year%4 == 0) ? ((year%100 == 0) ? ((year%400 == 0) ? 1 : 0) : 1): 0) + +int hello(void) +{ + puts("Hello world in a C function"); + + return 0; +} + +int day_of_week(int day, int month, int year) +{ + int count, sum_of_days; + + /* 1/1/2000 is Saturday */ + int first_day = 6; + + /* check input date */ + if (year < 2000) { + printf("Sorry buddy, your date should be >= 1/1/2000!\n"); + return -1; + } + + if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) { + if (day > 31 || day < 1) { + printf("Sorry buddy, your date is not correct!\n"); + return -1; + } + } + else if (month == 2) { + + if (IS_LEAP_YEAR(year)) { + if (day > 29 || day < 1) { + printf("Sorry buddy, your date is not correct!\n"); + return -1; + } + } + else { + if (day > 28 || day < 1) { + printf("Sorry buddy, your date is not correct!\n"); + return -1; + } + } + } + else { + if (day > 30 || day < 1) { + printf("Sorry buddy, your date is not correct!\n"); + return -1; + } + } + + /* date is okay, convert... */ + sum_of_days = 0; + + for (count = 2000; count < year; count++) { + sum_of_days += (((IS_LEAP_YEAR(count) == 1) ? 366 : 365)) % 7; + } + + for (count = 1; count < month; count++) { + if (count == 1 || count == 3 || count == 5 || count == 7 || count == 8 || count == 10 || count == 12) { + sum_of_days += 31 % 7; + } + else if (count == 2) { + + if (IS_LEAP_YEAR(year)) { + sum_of_days += 29 % 7; + } + else { + sum_of_days += 28 % 7; + } + } + else { + sum_of_days += 30 % 7; + } + } + + sum_of_days += (day - 1) % 7; + + return (sum_of_days + first_day) % 7; +} diff --git a/examples/riot_and_cpp/c_functions.h b/examples/riot_and_cpp/c_functions.h new file mode 100644 index 0000000000..ec0a0c3284 --- /dev/null +++ b/examples/riot_and_cpp/c_functions.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014 Ho Chi Minh city University of Technology (HCMUT) + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup examples + * @{ + * + * @file c_functions.h + * @brief Definitions for some c functions. + * + * @author DangNhat Pham-Huu <51002279@hcmut.edu.vn> + * + */ + +#include + +#ifndef C_FUNCTIONS_H_ +#define C_FUNCTIONS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Print a hello message. + */ +int hello(void); + +/** + * @brief Get day of week from given date (day, month, year >= 1/1/2000). + * + * @param[in] day + * @param[in] month + * @param[in] year + * + * @return day of week (0 means Sunday, ... 6 means Saturday) + */ +int day_of_week(int day, int month, int year); + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif // _C_FUNCTIONS_H diff --git a/examples/riot_and_cpp/cpp_class.cpp b/examples/riot_and_cpp/cpp_class.cpp new file mode 100644 index 0000000000..149d3cf35c --- /dev/null +++ b/examples/riot_and_cpp/cpp_class.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2014 Hamburg University of Applied Sciences (HAW) + * Copyright (C) 2014 Ho Chi Minh city University of Technology (HCMUT) + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup examples + * @{ + * + * @file cpp_class.cpp + * @brief implementation of declared functions of object cpp_class + * + * @author Martin Landsmann + * @author DangNhat Pham-Huu <51002279@hcmut.edu.vn> + * + * @} + */ + +#include "cpp_class.h" + +cpp_class::cpp_class() +{ + printf("Instanciating Object [constructor called]\n"); + greet(); +} + +cpp_class::~cpp_class() +{ + printf("Destroying Object [destructor called]\n"); + printf("Im shutting down!\n"); +} + +void cpp_class::say_hello(void) +{ + printf("Hello!\n"); +} + +void cpp_class::say_hello(int n) +{ + printf("Hello![int: %d]\n", n); +} + +void cpp_class::say_hello(float f) +{ + printf("Hello![float: %f]\n", f); +} + +void cpp_class::greet(void) +{ + printf("Im starting!\n"); +} diff --git a/examples/riot_and_cpp/cpp_class.h b/examples/riot_and_cpp/cpp_class.h new file mode 100644 index 0000000000..cd4004617a --- /dev/null +++ b/examples/riot_and_cpp/cpp_class.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2014 Hamburg University of Applied Sciences (HAW) + * Copyright (C) 2014 Ho Chi Minh city University of Technology (HCMUT) + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @defgroup + * @brief + * @ingroup examples + * @{ + * + * @file cpp_class.h + * @brief simple c++ object declaration with public and private functions + * + * @author Martin Landsmann + * @author DangNhat Pham-Huu <51002279@stu.hcmut.edu.vn> + */ + +#ifndef CPP_CLASS_H_ +#define CPP_CLASS_H_ + +#include + +class cpp_class +{ +public: + /** + * @brief constructor + */ + cpp_class(); + + /** + * @brief destructor + */ + ~cpp_class(); + + /** + * @brief public function + */ + void say_hello(void); + + /** + * @brief overloaded public function with int parameter + */ + void say_hello(int n); + + /** + * @brief overloaded public function with float parameter + */ + void say_hello(float f); +private: + /** + * @brief private function + */ + void greet(void); +}; + +/** @} */ +#endif //__CPP_CLASS__ diff --git a/examples/riot_and_cpp/main.cpp b/examples/riot_and_cpp/main.cpp new file mode 100644 index 0000000000..b40f631848 --- /dev/null +++ b/examples/riot_and_cpp/main.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2014 Hamburg University of Applied Sciences (HAW) + * Copyright (C) 2014 Ho Chi Minh University of Technology (HCMUT) + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @file main.cpp + * @brief Demonstration of mixed c++ and c user application with pure c RIOT + * - mixing of c and c++ source to test name mangling + * - introducing a namespace to declarative block, avoiding to qualify calls, e.g. std::vector + * - using private and public member functions, e.g. 'cpp_obj.greet()' cannot be accessed from main.cpp + * - overloading of function 'cpp_obj.say_hello(...)' for 'none', 'int' or 'float' + * - demonstration of templated c++ container 'std::vector' + * - usage of iterator to access elements of the container type + * + * @author Martin Landsmann + * @author DangNhat Pham-Huu <51002279@hcmut.edu.vn> + */ + +/* + * all included headers defining c functions, i.e. all RIOT functions, must be marked as extern "C" + */ +extern "C" { +#include "kernel.h" +#include "thread.h" + +#include "c_functions.h" +} + +#include +#include +#include "cpp_class.h" + +using namespace std; + +/* thread's stack */ +char threadA_stack [KERNEL_CONF_STACKSIZE_PRINTF]; + +/* thread's function */ +void threadA_func(void); + +/* main */ +int main() +{ + printf("\n************ RIOT and C++ demo program ***********\n"); + printf("\n"); + + /* create thread A */ + thread_create(threadA_stack, sizeof(threadA_stack), 0, CREATE_WOUT_YIELD, threadA_func, "thread A"); + + printf("******** Hello, you're in thread %s ********\n", thread_getname(thread_getpid())); + printf("We'll test C++ class and methods here!\n"); + + cpp_class cpp_obj; + printf("\n-= Test overloading functions =-\n"); + cpp_obj.say_hello(); + cpp_obj.say_hello(42); + cpp_obj.say_hello(3.141592f); + + printf("\n-= Test namespace =-\n"); + printf("typing std::vector is obsolete when 'using namespace std;'\n"); + vector vInts; + vInts.push_back(1); + vInts.push_back(3); + vInts.push_back(2); + printf("The vector vInts has been filled with %d numbers.\n", vInts.size()); + + printf("\n-= Test iterator =-\n"); + printf("The content of vInts = { "); + + for (vector::iterator it = vInts.begin(); it != vInts.end(); ++it) { + printf("%d ", *(it)); + } + + printf("}\n"); + + return 0; +} + +/* thread A function implemetation */ +void threadA_func(void) +{ + int day = 13, month = 6, year = 2014; + int ret_day; + char day_of_week_table[][32] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; + + printf("\n******** Hello, now you're in %s ********\n", thread_getname(thread_getpid())); + printf("We'll test some C functions here!\n"); + + printf("\n-= hello function =-\n"); + hello(); + + printf("\n-= day_of_week function =-\n"); + + printf("day %d, month %d, year %d is ", day, month, year); + + ret_day = day_of_week(day, month, year); + if (ret_day >= 0){ + printf("%s\n", day_of_week_table[ret_day]); + } + + printf("\nThis demo ends here, press Ctrl-C to exit (if you're on native)!\n"); +}