about summary refs log tree commit diff
path: root/pkgs/build-support/setup-hooks/multiple-outputs.sh
blob: ef199ae9cb57ed4a39371156487d3fb97fe4ea86 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# The base package for automatic multiple-output splitting. Used in stdenv as well.

preConfigureHooks+=(_multioutConfig)
preFixupHooks+=(_multioutDocs)
preFixupHooks+=(_multioutDevs)
postFixupHooks+=(_multioutPropagateDev)

# Assign the first string containing nonempty variable to the variable named $1
_assignFirst() {
    local varName="$1"
    shift
    while [ $# -ge 1 ]; do
        if [ -n "${!1}" ]; then eval "${varName}"="$1"; return; fi
        shift
    done
    return 1 # none found
}
# Same as _assignFirst, but only if "$1" = ""
_overrideFirst() {
    if [ -z "${!1}" ]; then
        _assignFirst "$@"
    fi
}


# Setup chains of sane default values with easy overridability.
# The variables are global to be usable anywhere during the build.

_overrideFirst outputDev "dev" "out"
_overrideFirst outputBin "bin" "out"

_overrideFirst outputInclude "$outputDev"

# so-libs are often among the main things to keep, and so go to $out
_overrideFirst outputLib "lib" "out"

_overrideFirst outputDoc "doc" "out"
# man and info pages are small and often useful to distribute with binaries
_overrideFirst outputMan "man" "doc" "$outputBin"
_overrideFirst outputInfo "info" "doc" "$outputMan"


# Add standard flags to put files into the desired outputs.
_multioutConfig() {
    if [ "$outputs" = "out" ] || [ -z "${setOutputFlags-1}" ]; then return; fi;

    configureFlags="\
        --bindir=${!outputBin}/bin --sbindir=${!outputBin}/sbin \
        --includedir=${!outputInclude}/include --oldincludedir=${!outputInclude}/include \
        --mandir=${!outputMan}/share/man --infodir=${!outputInfo}/share/info \
        --docdir=${!outputDoc}/share/doc \
        --libdir=${!outputLib}/lib --libexecdir=${!outputLib}/libexec \
        $configureFlags"

    installFlags="\
        pkgconfigdir=${!outputDev}/lib/pkgconfig \
        m4datadir=${!outputDev}/share/aclocal aclocaldir=${!outputDev}/share/aclocal \
        $installFlags"
}

# Add rpath prefixes to library paths, and avoid stdenv doing it for $out.
_addRpathPrefix "${!outputLib}"
NIX_NO_SELF_RPATH=1


# Move subpaths that match pattern $1 from under any output/ to the $2 output/
# Beware: only * ? [..] patterns are accepted.
_moveToOutput() {
    local patt="$1"
    local dstOut="$2"
    local output
    for output in $outputs; do
        if [ "${!output}" = "$dstOut" ]; then continue; fi
        local srcPath
        for srcPath in ${!output}/$patt; do
            if [ ! -e "$srcPath" ]; then continue; fi
            local dstPath="$dstOut${srcPath#${!output}}"
            echo "moving $srcPath to $dstPath"

            if [ -d "$dstPath" ] && [ -d "$srcPath" ]
            then # attempt directory merge
                mv -t "$dstPath" "$srcPath"/*
                rmdir "$srcPath"
            else # usual move
                mkdir -p $(readlink -m "$dstPath/..") # create the parent for $dstPath
                mv "$srcPath" "$dstPath"
            fi
        done
    done
}

# Move documentation to the desired outputs.
_multioutDocs() {
    if [ "$outputs" = "out" ]; then return; fi;
    echo "Looking for documentation to move between outputs"
    _moveToOutput share/man "${!outputMan}"
    _moveToOutput share/info "${!outputInfo}"
    _moveToOutput share/doc "${!outputDoc}"
    # outputs TODO: perhaps have outputDevDoc for developer docs
    # and maybe allow _moveToOutput move to "/dev/trash" or similar
    _moveToOutput share/gtk-doc "${!outputDoc}"

    # Remove empty share directory.
    if [ -d "$out/share" ]; then
        rmdir "$out/share" --ignore-fail-on-non-empty
    fi
}

# Move development-only stuff to the desired outputs.
_multioutDevs() {
    if [ "$outputs" = "out" ] || [ -z "${moveToDev-1}" ]; then return; fi;
    echo "Looking for development-only stuff to move to $outputDev"
    _moveToOutput include "${!outputInclude}"
    _moveToOutput lib/pkgconfig "${!outputDev}"
    _moveToOutput share/pkgconfig "${!outputDev}"

    # don't move libtool files yet
    #_moveToOutput "lib/*.la" "${!outputDev}"

    for f in "${!outputDev}"/{lib,share}/pkgconfig/*.pc; do
        echo "Patching '$f' includedir to output ${!outputInclude}"
        sed -i "/^includedir=/s,=\${prefix},=${!outputInclude}," "$f"
    done
}

# Make the first output (typically "dev") propagate other outputs needed for development.
# Take the first, because that's what one gets when putting the package into buildInputs.
# Note: during the build, probably only the "native" development packages are useful.
# With current cross-building setup, all packages are "native" if not cross-building.
_multioutPropagateDev() {
    if [ "$outputs" = "out" ]; then return; fi;

    local outputFirst
    for outputFirst in $outputs; do
        break
    done

    # Default value: propagate binaries, includes and libraries
    if [ -z "${propagatedOutputs+1}" ]; then
        local po_dirty="$outputBin $outputInclude $outputLib"
        set +o pipefail
        propagatedOutputs=`echo "$po_dirty" \
            | tr -s ' ' '\n' | grep -v -F "$outputFirst" \
            | sort -u | tr '\n' ' ' `
        set -o pipefail

    elif [ -z "$propagatedOutputs" ]; then
        return # variable was explicitly set to empty
    fi

    mkdir -p "${!outputFirst}"/nix-support
    for output in $propagatedOutputs; do
        echo -n " ${!output}" >> "${!outputFirst}"/nix-support/propagated-native-build-inputs
    done
}