D 2019-09-17T19:53:08.715 L XVFS\sBuild\sWalkthrough N text/x-markdown P ad09df452f38181cd402a33b90b86a073a58a06512117f6a394e1ec9a074488d U rkeene W 6162 # XVFS Build Walkthrough ## xvfs-create The script "`xvfs-create`" which is referenced below creates a C source file containing a local static structure and an `Xvfs__Init()` symbol. The C source file contains all the data from the specified directory, file names, contents, sizes, directory children. This C file can be compiled in a few different ways ("Client", "Standalone", and "Flexible") covered below. ## "Server" ### Description The "Server" mode is a single in-process handler for "`//xvfs:/`" and additional clients can call `Xvfs_Register()` to register their filesystem with that handler. This has the advantage of being more efficient since there are not one `Tcl_Filesystem` per extension which have to all be searched through but instead a single handler which uses a `Tcl_HashTable` to map the namespace to things which have called `Xvfs_Register()`. The "Server" mode thus has 2 symbols: 1. `Xvfs_Init()` which initializes the `Tcl_Filesystem` for all of "`//xvfs:/`" as well as setup the empty `Tcl_HashTable` 2. `Xvfs_Register()` which is for other extensions to call to register their name under "`//xvfs:/`" ### Build Output $ make xvfs.so cc -I. -DUSE_TCL_STUBS=1 -DXVFS_DEBUG -I/usr/include -DXVFS_MODE_SERVER -fPIC -g3 -ggdb3 -Wall -o xvfs.o -c xvfs-core.c cc -fPIC -g3 -ggdb3 -Wall -shared -o xvfs.so xvfs.o -L/usr/lib64 -ltclstub8.6 $ nm -D xvfs.so | grep ' [TU] ' 0000000000004a07 T Xvfs_Init 0000000000004c6a T Xvfs_Register U fprintf U memcmp U memcpy U stderr U strchr Here we can see that indeed the only defined symbols for relocation are `Xvfs_Init()` and `Xvfs_Register()`, as well as some undefined symbols which we rely on. The symbols `fprintf()` and `stderr` are only used for debugging and would not be required in a production build. ## "Client" ### Description The "Client" mode is very simple. It converts the specified directory ("example") into a C source file where all of the files contents and all directories children are structures of a local static structure. Then a `Xvfs_example_Init()` function is created which call `Xvfs_Register()` pointing to this structure (actually it points to some handlers so that the structure can change over time without relying on the core to be adaptable). The "Client" mode thus exports a single symbol, `Xvfs__Init()`, and relies on a single symbol from the "Server" mode, `Xvfs_Register()`. Once you `[load]` this extension the `Xvfs_example_Init()` function is called and the VFS is registered under `//xvfs:/example` for all interpreters in this process. ### Build Output $ make example-client.so ./xvfs-create --directory example --name example > example.c.new mv example.c.new example.c cc -I. -DUSE_TCL_STUBS=1 -DXVFS_DEBUG -I/usr/include -DXVFS_MODE_CLIENT -fPIC -g3 -ggdb3 -Wall -o example-client.o -c example.c cc -fPIC -g3 -ggdb3 -Wall -shared -o example-client.so example-client.o -L/usr/lib64 -ltclstub8.6 $ nm -D example-client.so | grep ' [TU] ' U Xvfs_Register 0000000000000ed5 T Xvfs_example_Init U memcmp U strlen ## "Standalone" ### Description The "Standalone" mode is a logically combined "Client" and "Server" mode. However, it does not check for anything already handling "`//xvfs:/`" and always registers its own `Tcl_Filesystem` handling only `//xvfs:/`. It does not export an `Xvfs_Register()` function and is completely standalone (hence the name). It will work and can be `[load]d` on any version of Tcl, the same as "Client" mode but with no external dependencies on the "Server" mode. The "Standalone" mode thus exports a single symbol, `Xvfs__Init()`. ### Build Output $ make example-standalone.so ./xvfs-create --directory example --name example > example.c.new mv example.c.new example.c cc -I. -DUSE_TCL_STUBS=1 -DXVFS_DEBUG -I/usr/include -DXVFS_MODE_STANDALONE -fPIC -g3 -ggdb3 -Wall -o example-standalone.o -c example.c cc -fPIC -g3 -ggdb3 -Wall -shared -o example-standalone.so example-standalone.o -L/usr/lib64 -ltclstub8.6 $ nm -D example-standalone.so | grep ' [TU] ' 0000000000004d26 T Xvfs_example_Init U fprintf U memcmp U memcpy U stderr U strlen ## "Flexible" ### Description The "Flexible" mode is a combination of "Standalone" and "Client modes. It will search for an existing handler of "`//xvfs:/`" and if so call that handler's `Xvfs_Register()` function. If no such handler exists it will invoke the same handler as "Standalone" mode and register its own `Tcl_Filesystem`. Because we cannot be linked with an undefined symbol to `Xvfs_Register()` the "Flexible" mode does not use the run-time linker to find the symbol for `Xvfs_Register()` but rather works with the Tcl VFS layer to locate that symbol dynamically. The "Flexible" mode thus exports a single symbol, `Xvfs__Init()` and has no hard requirements on dependent symbols, however the "Server" mode's `Xvfs_Register()` will be called if its `Xvfs_Init()` function has been called previously to register a handler for `//xvfs:/`. ### Build Output $ make example-flexible.so ./xvfs-create --directory example --name example > example.c.new mv example.c.new example.c cc -I. -DUSE_TCL_STUBS=1 -DXVFS_DEBUG -I/usr/include -DXVFS_MODE_FLEXIBLE -fPIC -g3 -ggdb3 -Wall -o example-flexible.o -c example.c cc -fPIC -g3 -ggdb3 -Wall -shared -o example-flexible.so example-flexible.o -L/usr/lib64 -ltclstub8.6 $ nm -D example-flexible.so | grep ' [TU] ' 00000000000050c8 T Xvfs_example_Init U fprintf U memcmp U memcpy U stderr U strlen Z 8cd0c9f5cdf194ca1b2df8228aa9e8a1