Source Code Structure
SAFplus source code is located under the "src" directory, examples are located under "examples". Every SAFplus library and component is located under the "src" directory. Special directories are as follows:
- The "src/include" directory contains ALL header files that an application will need when using SAFplus services. This is the ONLY directory that applications will need to include as a -I flag. You may create symbolic links from this directory to header files in component-specific subdirectories if you would like to keep your component header files in component directories.
- Third party open source software that is not generally provided by a Linux distribution is located in the "src/3rdparty" subdirectory.
- The "common" directory contains autogenerated YANG objects. Do not add anything here
- The "mk" directory contains all files need by the build system, except of course for the "Makefile" located to build in each directory. For more information see Makefile System.
- osal: Operating System Adaptation Layer. Use Boost for most of your OS functions. If boost does not have the needed feature, put it in here.
- utils: Put functions of general applicability in here.
Component source code structure
Inside a component directory code is structured as follows:
[component] [files to build the client library (if any)] server [files to build the server side of the component (if it has a server)] test [unit tests for this component]
Makefile System
Makefiles are structured so that a user can build in any subdirectory simply by typing "make". At the top, every Makefile includes the file "src/mk/preface.mk" which defines make variables that should be used in the rest of the makefile. At the bottom, every makefile includes "src/mk/safplus_targets.mk" which defines how other SAFplus targets (libraries, programs, tests) can be made.
Makefile Variables
These make variables are only set to values if they are not already set. They can be overridden via environment variables, make command line parameters, or via parent makefiles.
Source code Locations
These variables define where source code is located:
SAFPLUS_MAKE_DIR: the directory containing make related files, e.g. ".../src/mk"
SAFPLUS_SRC_DIR: the SAFplus source root directory, e.g. ".../src"
SAFPLUS_INC_DIR: the SAFplus include directory, e.g. ".../src/include". This is the only directory the applications need to include to get access to all SAFplus services headers.
SAFPLUS_3RDPARTY_DIR: the SAFplus 3rd party directory, e.g. ".../src/3rdparty"
Useful Inside Makefiles
TARGET_OS: what operating system are you building for? By default this is the output of "uname -r". You can override this variable to ensure that a crossbuild's output is put in a unique location.
TARGET_PLATFORM: what architecture are you building for? By default this is the output of "uname -p". You can override this variable to ensure that a crossbuild's output is put in a unique location.
LINK_SO_LIBS: The standard libraries that SAFplus needs in order to link
LINK_SO: How to create a shared library. Usage: $(LINK_SO) [output file] [input .o files and .so files]
LINK_EXE: How to create an executable program. Usage: $(LINK_EXE) [output file] [input .o and .so files]
Output Locations
By default all output files are stored in the directory ".../src/target/$(TARGET_OS)/$(TARGET_PLATFORM). This allows cross compiles to be output into a new directory so they do not interfere with eachother or the native compilation. The directory structure is as follows:
.../src/target/$(TARGET_OS)/$(TARGET_PLATFORM) lib : SAFplus libraries bin : SAFplus executables obj : .o files not part of libmw.so mwobj : .o files that are part of libmw.so test : unit tests install : install "prefix" for all 3rdparty code. Everything in here becomes part of the final package (unless the packager deliberately omits dev directories like "include"). bin include lib share [...and more...]
These variables define output target directories described above.
INSTALL_DIR: All 3rdparty make;make install output goes here, in the linux standard subdirectory structure (include,lib). This entire directory will become part of the final package so users can copy additional files into this subdirectory to include them.
LIB_DIR: SAFplus library output directory. Individual component libraries, plugins, and the full libmw.so will be generated into this directory. The packaging software can either choose to include just libmw.so, or include individual component libraries.
BIN_DIR: SAFplus executable files.
TEST_DIR: SAFplus unit tests.
OBJ_DIR: All object files that are NOT PART of libmw.so should go in this directory or in subdirectories.
MWOBJ_DIR: All object files that are PART of libmw.so should go here.
Makefile Detailed Structure
The following is an example Makefile, annotated:
It is necessary to uniquely identify this makefile because otherwise targets declared in this file will conflict with the target defined in safplus_targets.mk.
SAFPLUS_LOG_LIB:=1
Get the SAFplus variable definitions. If you want to override any of them, do it before including this file.
include ../mk/preface.mk
Here we find all the headers and source files that this component uses.
CLIENT_H := $(wildcard *.hxx) $(wildcard $(SAFPLUS_INC_DIR)/*.h) $(wildcard $(SAFPLUS_INC_DIR)/*.hxx) CLIENT_SRC := $(wildcard *.cxx)
Now transform those .cxx files into [output dir]/[filename].o
CLIENT_OBJ := $(subst .cxx,.o,$(CLIENT_SRC)) CLIENT_OBJ := $(addprefix $(MWOBJ_DIR)/,$(subst .cxx,.o,$(CLIENT_SRC)))
Now we specify all the libraries that this component needs, and then transform them into a list of dependency files. These files are specified in safplus_targets.mk which is how the makefile system is able to recursively build them. Application code would NOT do this for SAFplus libraries (you could use the same technique for your own libs). Instead just link with libmw.so and do a complete recompilation of SAFplus whenever you get a new release.
# Specify the required libraries SAFPLUS_LIBS := clOsal clUtils # Then use these in the make rule SAFPLUS_DEP_LIBS := $(addsuffix .so,$(addprefix $(LIB_DIR)/lib,$(SAFPLUS_LIBS))) SAFPLUS_LINK_LIBS := -L$(LIB_DIR) $(addprefix -l,$(SAFPLUS_LIBS))
Now define this makefile's targets
Release all: $(LIB_DIR)/libclLog.so
Finally define the build rules. It would be possible to define these build rules once in safplus_targets.mk. But leaving them in each Makefile makes customization easier.
$(SAFPLUS_TARGET)/lib/libclLog.so: $(CLIENT_OBJ) $(SAFPLUS_DEP_LIBS) $(LINK_SO) $@ $(CLIENT_OBJ) $(SAFPLUS_LINK_LIBS) $(LINK_SO_LIBS) $(MWOBJ_DIR)/%.o: %.cxx Makefile $(SERVER_H) $(COMPILE_CPP) $@ $<
Define a way to clean all the items that this makefile generates:
clean: rm -f $(SAFPLUS_TARGET)/lib/clLog.o $(CLIENT_OBJ)
Include the file that defines all the SAFplus target files. Every definition in this file simply spawns a recursive make to the appropriate subdirectory. Applications would typically not include this file since they do not need fine grain rebuilds of SAFplus.
include $(SAFPLUS_MAKE_DIR)/safplus_targets.mk
Checklist to add a SAFplus library or executable
- Create a subdirectory under src, following the component subdirectory structure
- Create makefiles in each directory, following the component makefile template
- Uniquely identify your each new makefile with a variable definition at the top
- Use variables defined in preface.mk to generate your targets into the correct output locations.
Add your targets to safplus_targets.mk, wrapping an "ifndef <makefile variable>" around your targets (use other target definitions in safplus_targets.mk to see what to do)
- If you are adding a SAFplus component library, it needs to be initialized as part of the safplusInitialize(...) call defined in clGlobals.hxx.
Add a new enum to LibSet,
- Add a new enum to libDep specifying dependencies. Remember, these dependencies define what the client library depends on, not the server.
- define a weakly bound initializer function
- call the initializer function at the appropriate place in safplusInitialize.