1 = L4Re Support = 2 3 The L4Re build system is based on Makefiles, and the `mk` directory within the 4 idl4re software distribution contains a collection of `make`-compatible files 5 that integrate the [[idl|`idl`]] tool and interface files with the L4Re build 6 system so that the tool is invoked automatically when necessary. 7 8 <<TableOfContents(2)>> 9 10 To write or adapt a package `Makefile`, some additional definitions and 11 statements are needed to introduce the additional processing steps that take 12 interface descriptions and generate source code from them when needed. 13 14 ######## A diagram showing the processing workflow... 15 16 {{{#!graphviz 17 #format svg 18 #transform notugly 19 digraph processing { 20 node [shape=folder,fontsize="12.0",fontname="sans-serif"]; 21 edge [fontsize="12.0",fontname="sans-serif"]; 22 rankdir=LR; 23 24 interface [label="Interface:\nfile.idl"]; 25 26 subgraph { 27 rank=same; 28 generated [label="Generated sources:\nfile_server.c\nfile_client.c\n..."]; 29 existing [label="Existing sources"]; 30 } 31 32 program [label="Output program"]; 33 34 interface -> generated [label="idl"]; 35 generated -> program; 36 existing -> program; 37 } 38 }}} 39 40 ######## End of diagram. 41 42 This document describes the form a package `Makefile` should take and 43 introduces the required elements to integrate interface code generation into 44 the package build process. 45 46 == Basic Makefile Structure == 47 48 The general form of a suitable `Makefile` employing interface generation 49 follows that broadly used within L4Re, with a top-level package employing the 50 following definitions: 51 52 {{{ 53 PKGDIR ?= . 54 L4DIR ?= $(PKGDIR)/../.. 55 }}} 56 57 Appropriate target and build mode definitions may be specified. For example, 58 for a program: 59 60 {{{ 61 TARGET = myserver 62 MODE = shared 63 }}} 64 65 For a library: 66 67 {{{ 68 TARGET = libserver.a libserver.so 69 }}} 70 71 Various locations and the inclusion of some rules are useful to define at this 72 point: 73 74 {{{ 75 IDL_DIR = $(L4DIR)/pkg/libsystypes/idl 76 IDL_MK_DIR = $(L4DIR)/idl4re/mk 77 IDL_BUILD_DIR = . 78 IDL_EXPORT_DIR = . 79 80 include $(IDL_MK_DIR)/idl.mk 81 }}} 82 83 (These are described below.) 84 85 Usage of interface descriptions should be defined. For example, for some 86 interfaces employed by client programs in the C language: 87 88 {{{ 89 CLIENT_INTERFACES_C = file mapped_file 90 }}} 91 92 For interfaces used by C++ server programs: 93 94 {{{ 95 SERVER_INTERFACES_CC = dataspace dataspace_factory 96 }}} 97 98 These interface definitions are then complemented with definitions that expand 99 to the source files involved. For example: 100 101 {{{ 102 CLIENT_INTERFACES_SRC_C = $(call interfaces_to_client_c,$(CLIENT_INTERFACES_C)) 103 }}} 104 105 Or: 106 107 {{{ 108 SERVER_INTERFACES_SRC_CC = $(call interfaces_to_server_cc,$(SERVER_INTERFACES_CC)) 109 }}} 110 111 After these definitions, it is convenient to provide the plain source files 112 that are present in the package. For example: 113 114 {{{ 115 PLAIN_SRC_C = routines.c main.c 116 }}} 117 118 With this, it is possible to provide the normal source file definitions which 119 will be a combination of the plain source files with the ones providing 120 support for interfaces. 121 122 For example, for a client program employing generated C language files: 123 124 {{{ 125 SRC_C = $(PLAIN_SRC_C) $(CLIENT_INTERFACES_SRC_C) 126 }}} 127 128 To make sure that any required headers are generated before attempts are made 129 to compile the source files, a special rule is required at the end of the 130 file. This is mentioned below. 131 132 Library-related and header-related definitions are typically needed. For 133 example: 134 135 {{{ 136 REQUIRES_LIBS = libipc libsystypes 137 PRIVATE_INCDIR = $(IDL_BUILD_DIR) $(IDL_EXPORT_DIR) 138 }}} 139 140 As usual, the `Makefile` ends with the appropriate role-specific rule 141 inclusion. For example, for programs: 142 143 {{{ 144 include $(L4DIR)/mk/prog.mk 145 }}} 146 147 For interface-driven file generation, an accompanying statement is 148 also required: 149 150 {{{ 151 include $(IDL_MK_DIR)/interface_rules.mk 152 }}} 153 154 This must appear after the role-specific inclusion statement. 155 156 Finally, to coordinate the generation of header files with compilation, a rule 157 must be added after the L4Re build system `include` statements. This must make 158 the plain source files dependent on generated files. For example: 159 160 {{{ 161 $(PLAIN_SRC_C): $(CLIENT_INTERFACES_SRC_C) 162 }}} 163 164 Or, for C++ server code, using the above naming conventions: 165 166 {{{ 167 $(PLAIN_SRC_CC): $(SERVER_INTERFACES_SRC_CC) 168 }}} 169 170 The following sections describe the different elements of this basic 171 arrangement in more detail. 172 173 == Interface-Related Settings == 174 175 In a Makefile used to build a L4Re component, the following settings can be 176 used to configure the generation of code from interfaces. 177 178 || '''Variable''' || '''Purpose''' || 179 || `IDL_DIR` || Finding `.idl` files to be processed || 180 || `IDL_MK_DIR` || Finding the `idl4re/mk` directory and rule files || 181 || `IDL_BUILD_DIR` || The location of generated code for this component || 182 || `IDL_EXPORT_DIR` || Exporting interface headers || 183 184 The roles of the variables can be summarised in a diagram: 185 186 ######## A diagram showing the locations and the flow of information... 187 188 {{{#!graphviz 189 #format svg 190 #transform notugly 191 digraph variables { 192 node [shape=folder,fontsize="12.0",fontname="sans-serif"]; 193 edge [fontsize="12.0",fontname="sans-serif"]; 194 rankdir=LR; 195 196 IDL_DIR [label="IDL_DIR\nfile.idl\n..."]; 197 IDL_BUILD_DIR [label="IDL_BUILD_DIR\nfile_client.c\n..."]; 198 IDL_EXPORT_DIR [label="IDL_EXPORT_DIR\nfile_interface.h\n..."]; 199 200 subgraph { 201 rank=same; 202 IDL_MK_DIR [label="IDL_MK_DIR\nidl.mk\n..."]; 203 idl [shape=ellipse]; 204 } 205 206 IDL_DIR -> idl -> IDL_BUILD_DIR; 207 IDL_MK_DIR -> idl [style=dashed]; 208 idl -> IDL_EXPORT_DIR; 209 } 210 }}} 211 212 ######## End of diagram. 213 214 Typically, the following kinds of values will be used: 215 216 || '''Variable''' || '''Value''' || 217 || `IDL_DIR` || A directory containing interfaces || 218 || `IDL_MK_DIR` || `$(L4DIR)/idl4re/mk` || 219 || `IDL_BUILD_DIR` || `.` || 220 || `IDL_EXPORT_DIR` || (See below for discussion.) || 221 222 In the case of `IDL_EXPORT_DIR`, the variable needs to indicate the location 223 of interface header files that can be referenced by code needing to use the 224 component interfaces. Where such code resides in the same package, the current 225 directory (`.`) can be used. Where such code resides in other packages, a 226 location is required to export the generated files to those packages. 227 228 To avoid mixing up any exported ''generated'' interface headers with original 229 ''non-generated'' headers, a value of the following form can be used: 230 231 {{{ 232 $(OBJ_BASE)/include/contrib/$(CONTRIB_INCDIR) 233 }}} 234 235 Here, a header called `file_interface.h` would be exported and included using 236 just this simple name. However, in some cases, there may be other packages 237 exporting headers of the same name, and this may result in confusion. 238 239 The solution to this is to organise headers (of any kind) in collections. 240 Here, the header could be placed inside a directory called `fsserver` and be 241 included as `fsserver/file_interface.h`. This would be achieved by using a 242 location of the following form: 243 244 {{{ 245 $(OBJ_BASE)/include/contrib/$(CONTRIB_INCDIR)/fsserver 246 }}} 247 248 == Filename Transformations == 249 250 Immediately after the settings, it is typically useful to define some filename 251 transformations: 252 253 {{{ 254 include $(IDL_MK_DIR)/idl.mk 255 }}} 256 257 These make it easier to define the various interfaces used by a component and 258 to derive the filenames involved using transformation functions such as the 259 following: 260 261 {{{ 262 $(call interfaces_to_client_cc,$(CLIENT_INTERFACES_CC)) 263 }}} 264 265 Remember that a conventional package `Makefile` will be concerned with source 266 files and their compilation. Since interface files will be used to generate 267 files that do not initially exist, knowledge about the names of these 268 generated source files needs to be applied to tell the build system which 269 files it will ultimately need to compile. 270 271 ######## A diagram showing filename transformations... 272 273 {{{#!graphviz 274 #format svg 275 #transform notugly 276 digraph transformations { 277 node [shape=box,fontsize="12.0",fontname="sans-serif"]; 278 edge [fontsize="12.0",fontname="sans-serif"]; 279 rankdir=LR; 280 281 interface [label="file.idl"]; 282 client [label="file_client.c"]; 283 server [label="file_server.c"]; 284 285 interface -> client [label="interfaces_to_client_c"]; 286 interface -> server [label="interfaces_to_server_c"]; 287 } 288 }}} 289 290 ######## End of diagram. 291 292 Various rules are applied in the build system to make sure that source files 293 are then handled appropriately. 294 295 == Interface Definitions == 296 297 After the settings and the inclusion of the `idl.mk` file, it is appropriate 298 to define certain variables describing the use of individual interfaces: 299 300 || '''Variable''' || '''Interface Usage''' || 301 || `CLIENT_INTERFACES_C` || C language client code || 302 || `CLIENT_INTERFACES_CC` || C++ language client code || 303 || `SERVER_INTERFACES_C` || C language server code || 304 || `SERVER_INTERFACES_CC` || C++ language server code || 305 306 These variables reference `.idl` files containing interface descriptions. For 307 example: 308 309 {{{ 310 SERVER_INTERFACES_CC = dataspace mapped_file 311 }}} 312 313 This indicates that server code in C++ will need to be generated from 314 `dataspace.idl` and `mapped_file.idl`, and rules are generated to ensure that 315 `make` becomes aware of this need. 316 317 The variables are then employed in filename transformations, described in more 318 detail elsewhere in this document.