xref: /openbmc/sdbusplus/tools/sdbus++-gen-meson (revision 4ac7e56e)
1#!/usr/bin/env bash
2
3set -e
4
5function show_usage {
6    cat \
7<<EOF
8Usage: $(basename "$0") [options] <command-args>*
9
10Generate meson.build files from a directory tree containing YAML files and
11facilitate building the sdbus++ sources.
12
13Options:
14    --help              - Display this message
15    --command <cmd>     - Command mode to execute (default 'meson').
16    --directory <path>  - Root directory of the YAML source (default '.').
17    --output <path>     - Root directory of the output (default '.').
18    --tool <path>       - Path to the processing tool (default 'sdbus++').
19    --version           - Display this tool's version string.
20
21Commands:
22    meson               - Generate a tree of meson.build files corresponding
23                          to the source YAML files.
24    cpp <intf>          - Generate the source files from a YAML interface.
25    markdown <intf>     - Generate the markdown files from a YAML interface.
26    version             - Display this tool's version string.
27
28EOF
29}
30
31## The version is somewhat arbitrary but is used to create a warning message
32## if a repository contains old copies of the generated meson.build files and
33## needs an update.  We should increment the version number whenever the
34## resulting meson.build would change.
35tool_version="sdbus++-gen-meson version 1"
36function show_version {
37    echo "$tool_version"
38}
39
40# Set up defaults.
41sdbuspp="sdbus++"
42outputdir="."
43cmd="meson"
44rootdir="."
45
46# Parse options.
47options="$(getopt -o hc:d:o:t:v --long help,command:,directory:,output:,tool:,version -- "$@")"
48eval set -- "$options"
49
50while true;
51do
52    case "$1" in
53        -h | --help)
54            show_usage
55            exit
56            ;;
57
58        -c | --command)
59            shift
60            cmd="$1"
61            shift
62            ;;
63
64        -d | --directory)
65            shift
66            rootdir="$1"
67            shift
68            ;;
69
70        -o | --output)
71            shift
72            outputdir="$1"
73            shift
74            ;;
75
76        -t | --tool)
77            shift
78            sdbuspp="$1"
79            shift
80            ;;
81
82        -v | --version)
83            show_version
84            exit
85            ;;
86
87        --)
88            shift
89            break
90            ;;
91    esac
92done
93
94## Create an initially empty meson.build file.
95## $1 - path to create meson.build at.
96function meson_empty_file {
97    mkdir -p "$1"
98    echo "# Generated file; do not modify." > "$1/meson.build"
99}
100
101## Create the root-level meson.build
102##
103## Inserts rules to run the available version of this tool to ensure the
104## version has not changed.
105function meson_create_root {
106    meson_empty_file "$outputdir"
107
108    cat >> "$outputdir/meson.build" \
109<<EOF
110sdbuspp_gen_meson_ver = run_command(
111    sdbuspp_gen_meson_prog,
112    '--version',
113).stdout().strip().split('\n')[0]
114
115if sdbuspp_gen_meson_ver != '$tool_version'
116    warning('Generated meson files from wrong version of sdbus++-gen-meson.')
117    warning(
118        'Expected "$tool_version", got:',
119        sdbuspp_gen_meson_ver
120    )
121endif
122
123EOF
124}
125
126## hash-tables to store:
127##      meson_paths - list of subdirectory paths for which an empty meson.build
128##                    has already been created.
129##      interfaces - list of interface paths which a YAML has been found and
130##                   which YAML types (interface, errors, etc.).
131declare -A meson_paths
132declare -A interfaces
133
134## Ensure the meson.build files to a path have been created.
135## $1 - The path requiring to be created.
136function meson_create_path {
137
138    meson_path="$outputdir"
139    prev_meson_path=""
140
141    # Split the path into segments.
142    for part in $(echo "$1" | tr '/' '\n');
143    do
144        prev_meson_path="$meson_path"
145        meson_path="$meson_path/$part"
146
147        # Create the meson.build for this segment if it doesn't already exist.
148        if [ "x" == "x${meson_paths[$meson_path]}" ];
149        then
150            meson_paths["$meson_path"]="1"
151            meson_empty_file "$meson_path"
152
153            # Add the 'subdir' link into the parent's meson.build.
154            # We need to skip adding the links into the 'root' meson.build
155            # because most repositories want to selectively add TLDs based
156            # on config flags.  Let them figure out their own logic for that.
157            if [ "x$outputdir" != "x$prev_meson_path" ];
158            then
159                echo "subdir('$part')" >> "$prev_meson_path/meson.build"
160            fi
161        fi
162    done
163}
164
165## Generate the meson target for the source files (.cpp/.hpp) from a YAML
166## interface.
167##
168## $1 - The interface to generate a target for.
169function meson_cpp_target {
170
171    # Determine the source and output files based on the YAMLs present.
172    sources=""
173    outputs=""
174    for s in ${interfaces[$1]};
175    do
176        sources="${sources}meson.source_root() / '$1.$s', "
177
178        case "$s" in
179            errors.yaml)
180                outputs="${outputs}'error.cpp', 'error.hpp', "
181                ;;
182
183            interface.yaml)
184                outputs="${outputs}'server.cpp', 'server.hpp', "
185                outputs="${outputs}'client.hpp', "
186                ;;
187        esac
188    done
189
190    # Create the target to generate the 'outputs'.
191    cat >> "$outputdir/$1/meson.build" \
192<<EOF
193generated_sources += custom_target(
194    '$1__cpp'.underscorify(),
195    input: [ $sources ],
196    output: [ $outputs ],
197    command: [
198        sdbuspp_gen_meson_prog, '--command', 'cpp',
199        '--output', meson.current_build_dir(),
200        '--tool', sdbusplusplus_prog,
201        '--directory', meson.source_root(),
202        '$1',
203    ],
204)
205
206EOF
207}
208
209## Generate the meson target for the markdown files from a YAML interface.
210## $1 - The interface to generate a target for.
211function meson_md_target {
212
213    # Determine the source files based on the YAMLs present.
214    sources=""
215    for s in ${interfaces[$1]};
216    do
217        sources="${sources}meson.source_root() / '$1.$s', "
218    done
219
220    # Create the target to generate the interface.md file.
221    cat >> "$outputdir/$(dirname "$1")/meson.build" \
222<<EOF
223generated_others += custom_target(
224    '$1__markdown'.underscorify(),
225    input: [ $sources ],
226    output: [ '$(basename "$1").md' ],
227    command: [
228        sdbuspp_gen_meson_prog, '--command', 'markdown',
229        '--output', meson.current_build_dir(),
230        '--tool', sdbusplusplus_prog,
231        '--directory', meson.source_root(),
232        '$1',
233    ],
234    build_by_default: true,
235)
236
237EOF
238}
239
240## Handle command=meson by generating the tree of meson.build files.
241function cmd_meson {
242    TLDs="com net org xyz"
243    yamls=""
244
245    # Find all the YAML files in the TLD subdirectories.
246    for d in $TLDs;
247    do
248        dir="$rootdir/$d"
249        if [ ! -d "$dir" ];
250        then
251            continue
252        fi
253
254        yamls="\
255            $yamls \
256            $(find "$dir" -name '*.interface.yaml' -o -name '*.errors.yaml') \
257            "
258    done
259
260    # Sort YAMLs
261    yamls="$(echo "$yamls" | tr " " "\n" | sort)"
262
263    # Assign the YAML files into the hash-table by interface name.
264    for y in $yamls;
265    do
266        rel="$(realpath "--relative-to=$rootdir" "$y")"
267        dir="$(dirname "$rel")"
268        ext="${rel#*.}"
269        base="$(basename "$rel" ".$ext")"
270
271        interfaces["$dir/$base"]="${interfaces[$dir/$base]} $ext"
272    done
273
274    # Create the meson.build files.
275    meson_create_root
276    sorted_ifaces="$(echo "${!interfaces[@]}" | tr " " "\n" | sort)"
277    for i in ${sorted_ifaces};
278    do
279        meson_create_path "$i"
280        meson_cpp_target "$i"
281        meson_md_target "$i"
282    done
283}
284
285## Handle command=cpp by calling sdbus++ as appropriate.
286## $1 - interface to generate.
287##
288## For an interface foo/bar, the outputdir is expected to be foo/bar.
289function cmd_cpp {
290
291    if [ "x" == "x$1" ];
292    then
293        show_usage
294        exit 1
295    fi
296
297    if [ ! -e "$rootdir/$1.interface.yaml" ] && \
298        [ ! -e "$rootdir/$1.errors.yaml" ];
299    then
300        echo "Missing YAML for $1."
301        exit 1
302    fi
303
304    mkdir -p "$outputdir"
305
306    sdbusppcmd="$sdbuspp -r $rootdir"
307    intf="${1//\//.}"
308
309    if [ -e "$rootdir/$1.interface.yaml" ];
310    then
311        $sdbusppcmd interface server-header "$intf" > "$outputdir/server.hpp"
312        $sdbusppcmd interface server-cpp "$intf" > "$outputdir/server.cpp"
313        $sdbusppcmd interface client-header "$intf" > "$outputdir/client.hpp"
314    fi
315
316    if [ -e "$rootdir/$1.errors.yaml" ];
317    then
318        $sdbusppcmd error exception-header "$intf" > "$outputdir/error.hpp"
319        $sdbusppcmd error exception-cpp "$intf" > "$outputdir/error.cpp"
320    fi
321}
322
323## Handle command=markdown by calling sdbus++ as appropriate.
324## $1 - interface to generate.
325##
326## For an interface foo/bar, the outputdir is expected to be foo.
327function cmd_markdown {
328
329    if [ "x" == "x$1" ];
330    then
331        show_usage
332        exit 1
333    fi
334
335    if [ ! -e "$rootdir/$1.interface.yaml" ] && \
336        [ ! -e "$rootdir/$1.errors.yaml" ];
337    then
338        echo "Missing YAML for $1."
339        exit 1
340    fi
341
342    mkdir -p "$outputdir"
343
344    sdbusppcmd="$sdbuspp -r $rootdir"
345    intf="${1//\//.}"
346    base="$(basename "$1")"
347
348    echo -n > "$outputdir/$base.md"
349    if [ -e "$rootdir/$1.interface.yaml" ];
350    then
351        $sdbusppcmd interface markdown "$intf" >> "$outputdir/$base.md"
352    fi
353
354    if [ -e "$rootdir/$1.errors.yaml" ];
355    then
356        $sdbusppcmd error markdown "$intf" >> "$outputdir/$base.md"
357    fi
358}
359
360## Handle command=version.
361function cmd_version {
362    show_version
363}
364
365"cmd_$cmd" "$*"
366