summaryrefslogtreecommitdiffstats
path: root/m4macros/ax_find_library.m4
blob: 60247ad0aff4faa3fd5a2a47fb9ebda85f778c8f (plain)
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
######################### public functions ##########################

# input:
#   * value of --with-library
#   * list of headers to check
#   * list of libraries to check
#   * list of variables to retrieve with pkg-config
#   * additional parameters to pass to pkg-config, useful e.g. when --with-path
#       is needed to point to a dependency of the checked library
# output:
#   * LIBRARY_FOUND
#   * LIBRARY_CPPFLAGS
#   * LIBRARY_INCLUDEDIR
#   * LIBRARY_LIBS
#   * LIBRARY_PREFIX
#
# This function assumes that you have called AC_MSG_CHECKING() before and that
# you are responsible for calling AC_MSG_RESULT() if LIBRARY_FOUND is false or
# if any other checks that you do outside of this function fail. AC_MSG_RESULT()
# will be called in this function in case of fatal errors.
AC_DEFUN([AX_FIND_LIBRARY], [
  library=$1
  with_library=$2
  list_of_headers=$3
  list_of_libraries=$4
  list_of_variables=$5
  pkg_config_paths=$6

  LIBRARY_FOUND=false
  AX_RESET_LIBRARY_WARNINGS()

  if test -z "${with_library}"; then
    # library not requested, nothing to do
    :
  elif test "${with_library}" = 'no'; then
    # library specifically disabled, nothing to do
    :
  elif test "${with_library}" != 'yes'; then
    # library enabled and has custom --with parameter

    if test -f "${with_library}"; then
      # User has pointed --with-library to a file.
      # It might be a .pc file.
      AX_FIND_LIBRARY_WITH_PKG_CONFIG(["${with_library}"], ["${list_of_variables}"], ["${pkg_config_paths}"])

    elif test -d "${with_library}"; then
      # User has pointed --with-library to a directory.
      # Let's try to find a library.pc first inside that directory.
      for l in lib lib64; do
        library_pc="${with_library}/${l}/pkgconfig/${library}.pc"
        if test -f "${library_pc}"; then
          if test -n "${PKG_CONFIG}"; then
            AX_FIND_LIBRARY_WITH_PKG_CONFIG("${library_pc}", ["${list_of_variables}"], ["${pkg_config_paths}"])
          else
            AX_ADD_TO_LIBRARY_WARNINGS([pkg-config file found at ${library_pc}, but pkg-config is not available])
          fi
        else
          AX_ADD_TO_LIBRARY_WARNINGS([pkg-config file not found at ${library_pc}])
        fi
      done
    else
      AC_MSG_RESULT(["no"])
      AX_DISPLAY_LIBRARY_WARNINGS()
      AC_MSG_ERROR(["${with_library}" needs to point to the installation directory or to a .pc file])
    fi

  else
    # No parameter given. Try pkg-config first.
    if test -n "${PKG_CONFIG}"; then
      AX_FIND_LIBRARY_WITH_PKG_CONFIG("${library}", ["${list_of_variables}"], ["${pkg_config_paths}"])
    fi

    # If not found, then search in usual paths for a .pc file.
    if ! "${LIBRARY_FOUND}"; then
      for p in /usr /usr/local; do
        for l in lib lib64; do
          library_pc="${p}/${l}/pkgconfig/${library}.pc"
          if test -f "${library_pc}"; then
            AX_FIND_LIBRARY_WITH_PKG_CONFIG("${library_pc}", ["${list_of_variables}"], ["${pkg_config_paths}"])
            if "${LIBRARY_FOUND}"; then
              break 2
            fi
          fi
        done
      done
    fi

    # If not found, then search in usual paths for header and libraries.
    if ! "${LIBRARY_FOUND}"; then
      for p in /usr /usr/local; do
        headers_found=true
        for i in ${list_of_headers}; do
          if test ! -f "${p}/include/${i}"; then
            AX_ADD_TO_LIBRARY_WARNINGS([${library} header ${i} not found in ${p}])
            headers_found=false
            break
          fi
        done
        if "${headers_found}"; then
          LIBRARY_CPPFLAGS=
          LIBRARY_INCLUDEDIR="-I${p}/include"
        fi

        libraries_found=true

        # Add -L.
        for l in lib lib64; do
          if test -d "${p}/${l}"; then
            LIBRARY_LIBS="-L${p}/{l}"
          fi
        done
        for i in ${list_of_libraries}; do
          i_found=false
          for l in lib lib64; do
            if test -f "${p}/${l}/${i}"; then
              lib=$(printf '%s' "${i}" | sed 's/^lib//g;s/.so$//g')
              LIBRARY_LIBS="${LIBRARY_LIBS} -l${lib}"
              i_found=true
              break
            else
              AX_ADD_TO_LIBRARY_WARNINGS([${library} library ${i} not found in ${p}/${l}])
            fi
          done
          if ! "${i_found}"; then
            libraries_found=false
            break
          fi
        done

        if "${headers_found}" && "${libraries_found}"; then
          LIBRARY_FOUND=true
          break
        fi

      done
    fi
  fi

  if "${LIBRARY_FOUND}"; then
    # Remove leading and trailing spaces.
    LIBRARY_CPPFLAGS="$(printf '%s' "${LIBRARY_CPPFLAGS}" | sed 's/^ *//g;s/ *$//g')"
    LIBRARY_INCLUDEDIR="$(printf '%s' "${LIBRARY_INCLUDEDIR}" | sed 's/^ *//g;s/ *$//g')"
    LIBRARY_LIBS="$(printf '%s' "${LIBRARY_LIBS}" | sed 's/^ *//g;s/ *$//g')"

    # Add to the runtime search path if the flag is not already added.
    if test -n "${ISC_RPATH_FLAG}" && test "$(printf '%s\n' "${LIBRARY_LIBS}" | grep -Fc -- "${ISC_RPATH_FLAG}")" = 0; then
      library_location=$(printf '%s\n' "${LIBRARY_LIBS}" | grep -Eo -- '-L.*\b' | sed 's/-L//g')
      if test -n "${library_location}"; then
        LIBRARY_LIBS="${LIBRARY_LIBS} ${ISC_RPATH_FLAG}${library_location}"
      fi
    fi
  fi
])

# You usually want to call this after you have called AC_MSG_RESULT so that the
# warnings don't interfere between the text displayed by AC_MSG_CHECKING
# "checking library..." and the text displayed by AC_MSG_RESULT "yes" or "no"
# that should be on the same line.
AC_DEFUN([AX_DISPLAY_LIBRARY_WARNINGS], [
  if test -n "${LIBRARY_WARNINGS}"; then
    printf '%s\n' "${LIBRARY_WARNINGS}" | while read -r line; do
      AC_MSG_WARN([${line}])
    done
  fi
])

######################### private functions #########################

# input:
#   * value of --with-library
#   * list of variables to retrieve with pkg-config
#   * additional colon-separated paths to pass to pkg-config,
#       for when a .pc file has a dependency
# output:
#   * LIBRARY_FOUND
#   * LIBRARY_CPPFLAGS
#   * LIBRARY_INCLUDEDIR
#   * LIBRARY_LIBS
#   * LIBRARY_PREFIX
AC_DEFUN([AX_FIND_LIBRARY_WITH_PKG_CONFIG], [
  library_pc_or_name=$1
  list_of_variables=$2
  pkg_config_paths=$3

  LIBRARY_FOUND=false
  # Check that we have pkg-config installed on the system.
  if test -n "${PKG_CONFIG}"; then

    # Save the previous PKG_CONFIG_PATH.
    save_pkg_config_path="${PKG_CONFIG_PATH}"

    # If file was given, append its residing directory to PKG_CONFIG_PATH.
    # Some old versions of pkg-config (e.g. 0.29.1 in Ubuntu 20.04) seem to
    # require it when searching for dependencies.
    if test -f "${library_pc_or_name}"; then
      pkg_config_paths="${pkg_config_paths}:$(dirname "${library_pc_or_name}")"
    fi

    # Append some usual paths and the requested paths.
    export PKG_CONFIG_PATH="${PKG_CONFIG_PATH}:/usr/lib/pkgconfig:/usr/local/lib/pkgconfig:/usr/lib64/pkgconfig:/usr/local/lib64/pkgconfig:${pkg_config_paths}"

    # Check that pkg-config is able to interpret the file.
    if "${PKG_CONFIG}" "${library_pc_or_name}" > /dev/null 2>&1; then
      # Get the flags.
      LIBRARY_CPPFLAGS=$("${PKG_CONFIG}" --cflags-only-other "${library_pc_or_name}")
      LIBRARY_INCLUDEDIR=$("${PKG_CONFIG}" --cflags-only-I "${library_pc_or_name}")
      LIBRARY_LIBDIR=$("${PKG_CONFIG}" --variable libdir "${library_pc_or_name}")
      LIBRARY_LIBS=$("${PKG_CONFIG}" --libs "${library_pc_or_name}")
      LIBRARY_VERSION=$("${PKG_CONFIG}" --modversion "${library_pc_or_name}")
      LIBRARY_PREFIX=$("${PKG_CONFIG}" --variable=prefix "${library_pc_or_name}")

      # Sometimes pkg-config is stubborn in including -L, so let's include it ourselves.
      if test -n "${LIBRARY_LIBDIR}" && test "$(printf '%s\n' "${LIBRARY_LIBS}" | grep -Fc -- -L)" = 0; then
        LIBRARY_LIBS="-L${LIBRARY_LIBDIR} ${LIBRARY_LIBS}"
      fi

      # Get the variables.
      for i in $(printf '%s' "${list_of_variables}" | sed 's/,/ /g'); do
        # The export is not strictly required here, but we need a way to
        # dynamically assign values to "${i}". And export is nicer than eval.
        export "${i}"="$("${PKG_CONFIG}" --variable="${i}" "${library_pc_or_name}")"
      done

      # Mark that we have the required flags for our library.
      LIBRARY_FOUND=true
    fi

    # Restore the previous PKG_CONFIG_PATH.
    PKG_CONFIG_PATH="${save_pkg_config_path}"
  fi
])

AC_DEFUN([AX_ADD_TO_LIBRARY_WARNINGS], [
  if test -n "${LIBRARY_WARNINGS}"; then
    LIBRARY_WARNINGS="${LIBRARY_WARNINGS}
"
  fi
  LIBRARY_WARNINGS="${LIBRARY_WARNINGS}$1"
])

AC_DEFUN([AX_RESET_LIBRARY_WARNINGS], [
  LIBRARY_WARNINGS=
])