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:

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:

Useful Inside Makefiles

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.

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

  1. Create a subdirectory under src, following the component subdirectory structure
  2. Create makefiles in each directory, following the component makefile template
    1. Uniquely identify your each new makefile with a variable definition at the top
    2. Use variables defined in preface.mk to generate your targets into the correct output locations.
  3. 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)

  4. If you are adding a SAFplus component library, it needs to be initialized as part of the safplusInitialize(...) call defined in clGlobals.hxx.
    1. Add a new enum to LibSet,

    2. Add a new enum to libDep specifying dependencies. Remember, these dependencies define what the client library depends on, not the server.
    3. define a weakly bound initializer function
    4. call the initializer function at the appropriate place in safplusInitialize.

SAFplus: Source Code Structure and Makefile System (last edited 2015-03-09 18:11:38 by AndrewStone)