| 1 | --- |
| 2 | id: dynamic-linking |
| 3 | --- |
| 4 | |
| 5 | The second approach to package the tracepoint providers is to use |
| 6 | dynamic linking: the library and its member functions are explicitly |
| 7 | sought, loaded and unloaded at runtime using `libdl`. |
| 8 | |
| 9 | It has to be noted that, for a variety of reasons, the created shared |
| 10 | library will be dynamically _loaded_, as opposed to dynamically |
| 11 | _linked_. The tracepoint provider shared object is, however, linked |
| 12 | with `liblttng-ust`, so that `liblttng-ust` is guaranteed to be loaded |
| 13 | as soon as the tracepoint provider is. If the tracepoint provider is |
| 14 | not loaded, since the application itself is not linked with |
| 15 | `liblttng-ust`, the latter is not loaded at all and the tracepoint calls |
| 16 | become inert. |
| 17 | |
| 18 | The process to create the tracepoint provider shared object is pretty |
| 19 | much the same as the static library method, except that: |
| 20 | |
| 21 | * since the tracepoint provider is not part of the application |
| 22 | anymore, `TRACEPOINT_DEFINE` _must_ be defined, for each tracepoint |
| 23 | provider, in exactly one translation unit (C source file) of the |
| 24 | _application_; |
| 25 | * `TRACEPOINT_PROBE_DYNAMIC_LINKAGE` must be defined next to |
| 26 | `TRACEPOINT_DEFINE`. |
| 27 | |
| 28 | Regarding `TRACEPOINT_DEFINE` and `TRACEPOINT_PROBE_DYNAMIC_LINKAGE`, |
| 29 | the recommended practice is to use a separate C source file in your |
| 30 | application to define them, and then include the tracepoint provider |
| 31 | header files afterwards, e.g.: |
| 32 | |
| 33 | ~~~ c |
| 34 | #define TRACEPOINT_DEFINE |
| 35 | #define TRACEPOINT_PROBE_DYNAMIC_LINKAGE |
| 36 | |
| 37 | /* include the header files of one or more tracepoint providers below */ |
| 38 | #include "tp1.h" |
| 39 | #include "tp2.h" |
| 40 | #include "tp3.h" |
| 41 | ~~~ |
| 42 | |
| 43 | `TRACEPOINT_PROBE_DYNAMIC_LINKAGE` makes the macros included afterwards |
| 44 | (by including the tracepoint provider header, which itself includes |
| 45 | LTTng-UST headers) aware that the tracepoint provider is to be loaded |
| 46 | dynamically and not part of the application's executable. |
| 47 | |
| 48 | The tracepoint provider object file used to create the shared library |
| 49 | is built like it is using the static library method, only with the |
| 50 | `-fpic` option added: |
| 51 | |
| 52 | <pre class="term"> |
| 53 | gcc -c <strong>-fpic</strong> -I. tp.c |
| 54 | </pre> |
| 55 | |
| 56 | It is then linked as a shared library like this: |
| 57 | |
| 58 | <pre class="term"> |
| 59 | gcc <strong>-shared -Wl,--no-as-needed -o tp.so -llttng-ust</strong> tp.o |
| 60 | </pre> |
| 61 | |
| 62 | As previously stated, this tracepoint provider shared object isn't |
| 63 | linked with the user application: it will be loaded manually. This is |
| 64 | why the application is built with no mention of this tracepoint |
| 65 | provider, but still needs `libdl`: |
| 66 | |
| 67 | <pre class="term"> |
| 68 | gcc -o app other.o files.o of.o your.o app.o <strong>-ldl</strong> |
| 69 | </pre> |
| 70 | |
| 71 | Now, to make LTTng-UST tracing available to the application, |
| 72 | the `LD_PRELOAD` environment variable is used to preload the |
| 73 | tracepoint provider shared library _before_ the application actually |
| 74 | starts: |
| 75 | |
| 76 | <pre class="term"> |
| 77 | <strong>LD_PRELOAD=/path/to/tp.so</strong> ./app |
| 78 | </pre> |
| 79 | |
| 80 | Your application will still work without this preloading, albeit without |
| 81 | LTTng-UST tracing support: |
| 82 | |
| 83 | <pre class="term"> |
| 84 | ./app |
| 85 | </pre> |
| 86 | |