ErlangExports = erlang:module_info(exports),
Check = fun({F, A}) when is_atom(F), is_integer(A), A >= 0 ->
            erlang:is_builtin(erlang, F, A) orelse lists:member({F, A}, ErlangExports);
           ({M, F, A}) when is_atom(M), is_atom(F), is_integer(A), A >= 0 ->
            erlang:is_builtin(M, F, A) orelse (catch lists:member({F, A}, M:module_info(exports))) =:= true
        end,

BIFs = [{atom_to_binary, 1},
        {binary_to_atom, 1},
        {binary_to_existing_atom, 1},
        {ceil, 1},
        {error, 3},
        {floor, 1},
        {term_to_iovec, 1},
        {term_to_iovec, 2}],
Funs = [{application, get_supervisor, 1},
        {application, set_env, 1},
        {application, set_env, 2},
        {application_controller, set_env, 2},
        {argparse, format_error, 1},
        {argparse, format_error, 2},
        {argparse, help, 1},
        {argparse, help, 2},
        {argparse, parse, 2},
        {argparse, parse, 3},
        {argparse, run, 3},
        {argparse, validate, 1},
        {argparse, validate, 2},
        {beam_lib, significant_chunks, 0},
        {beam_lib, strip, 2},
        {beam_lib, strip_files, 2},
        {beam_lib, strip_release, 2},
        {binary, decode_hex, 1},
        {binary, encode_hex, 1},
        {binary, encode_hex, 2},
        {c, c, 3},
        {c, erlangrc, 1},
        {c, h, 1},
        {c, h, 2},
        {c, h, 3},
        {c, hcb, 1},
        {c, hcb, 2},
        {c, hcb, 3},
        {c, ht, 1},
        {c, ht, 2},
        {c, ht, 3},
        {c, lm, 0},
        {calendar, rfc3339_to_system_time, 1},
        {calendar, rfc3339_to_system_time, 2},
        {calendar, system_time_to_local_time, 2},
        {calendar, system_time_to_rfc3339, 1},
        {calendar, system_time_to_rfc3339, 2},
        {calendar, system_time_to_universal_time, 2},
        {code, add_path, 2},
        {code, add_patha, 2},
        {code, add_paths, 2},
        {code, add_pathsa, 2},
        {code, add_pathsz, 2},
        {code, add_pathz, 2},
        {code, all_available, 0},
        {code, clear_cache, 0},
        {code, del_paths, 1},
        {code, get_doc, 1},
        {code, is_module_native, 1},
        {code, lib_dir, 2},
        {code, modified_modules, 0},
        {code, module_status, 0},
        {code, module_status, 1},
        {code, rehash, 0},
        {code, replace_path, 3},
        {code, set_path, 2},
        {compile, iofile, 1},
        {crypto, block_decrypt, 3},
        {crypto, block_decrypt, 4},
        {crypto, block_encrypt, 3},
        {crypto, block_encrypt, 4},
        {crypto, cipher_info, 1},
        {crypto, cmac, 3},
        {crypto, cmac, 4},
        {crypto, crypto_one_time, 4},
        {crypto, crypto_one_time, 5},
        {crypto, dss_sign, 2},
        {crypto, dss_sign, 3},
        {crypto, dss_verify, 3},
        {crypto, dss_verify, 4},
        {crypto, hash_equals, 2},
        {crypto, hash_info, 1},
        {crypto, hmac, 3},
        {crypto, hmac, 4},
        {crypto, hmac_init, 2},
        {crypto, hmac_final, 1},
        {crypto, hmac_final_n, 2},
        {crypto, hmac_update, 2},
        {crypto, mac, 3},
        {crypto, mac, 4},
        {crypto, macN, 4},
        {crypto, macN, 5},
        {crypto, md4, 1},
        {crypto, md4_init, 0},
        {crypto, md5, 1},
        {crypto, md5_init, 0},
        {crypto, poly1305, 2},
        {crypto, rsa_sign, 2},
        {crypto, rsa_sign, 3},
        {crypto, rsa_verify, 3},
        {crypto, rsa_verify, 4},
        {crypto, sha, 1},
        {crypto, sha_init, 0},
        {crypto, sha224, 1},
        {crypto, sha256, 1},
        {crypto, sha384, 1},
        {crypto, sha512, 1},
        {crypto, sha224_init, 0},
        {crypto, sha256_init, 0},
        {crypto, sha384_init, 0},
        {crypto, sha512_init, 0},
        {crypto, sha224_mac, 2},
        {crypto, sha224_mac, 3},
        {crypto, sha256_mac, 2},
        {crypto, sha256_mac, 3},
        {crypto, sha384_mac, 2},
        {crypto, sha384_mac, 3},
        {crypto, sha512_mac, 2},
        {crypto, sha512_mac, 3},
        {crypto, stream_init, 2},
        {crypto, stream_init, 3},
        {crypto, stream_decrypt, 2},
        {crypto, stream_encrypt, 2},
        {crypto, supports, 1},
        {ct, get_progname, 0},
        {edlin, keymap, 0},
        {epp, scan_file, 1},
        {epp, scan_file, 2},
        {diameter, which_connections, 0},
        {diameter, which_connections, 1},
        {diameter, which_transports, 0},
        {diameter, which_transports, 1},
        {diameter, which_watchdogs, 0},
        {diameter, which_watchdogs, 1},
        {diameter_config, which_transports, 0},
        {diameter_config, which_transports, 1},
        {diameter_service, which_connections, 0},
        {diameter_service, which_connections, 1},
        {diameter_service, which_watchdogs, 0},
        {diameter_service, which_watchdogs, 1},
        {dict, foreach, 2},
        {dict, take, 2},
        {disk_log, accessible_logs, 0},
        {disk_log, lclose, 2},
        {erl_error, format_exception, 3},
        {erl_error, format_exception, 4},
        {erl_error, format_exception, 7},
        {erl_eval, extended_parse_exprs, 1},
        {erl_eval, extended_parse_term, 1},
        {erl_eval, subst_values_for_vars, 2},
        {erl_features, all, 0},
        {erl_features, configurable, 0},
        {erl_features, enabled, 0},
        {erl_features, info, 0},
        {erl_features, long, 0},
        {erl_features, short, 0},
        {erl_features, used, 0},
        {erl_internal, add_predefined_functions, 1},
        {erl_pp, legalize_vars, 1},
        {erlang, get_stacktrace, 0},
        {erlang, get_cookie, 1},
        {erlang, iolist_to_iovec, 1},
        {erlang, set_cookie, 1},
        {error_logger, get_format_depth, 0},
        {error_logger, limit_term, 1},
        {erts_internal, binary_to_integer, 2},
        {erts_internal, list_to_integer, 2},
        {erts_internal, map_next, 3},
        {ets, first_lookup, 1},
        {ets, last_lookup, 1},
        {ets, lookup_element, 4},
        {ets, next_lookup, 2},
        {ets, prev_lookup, 2},
        {ets, whereis, 1},
        {file, del_dir_r, 1},
        {file, delete, 2},
        {file, pid2name, 1},
        {file, read_file, 2},
        {filelib, ensure_path, 1},
        {filelib, find_file, 2},
        {filelib, find_file, 3},
        {filelib, safe_relative_path, 2},
        {filelib, find_source, 1},
        {filelib, find_source, 2},
        {filelib, find_source, 3},
        {filename, basedir, 2},
        {filename, basedir, 3},
        {filename, safe_relative_path, 1},
        {gb_sets, filtermap, 2},
        {gb_sets, foreach, 2},
        {gb_sets, is_equal, 2},
        {gb_sets, map, 2},
        {gb_trees, foreach, 2},
        {gb_trees, take, 2},
        {gb_trees, take_any, 2},
        {gen, debug_options, 1},
        {gen, debug_options, 2},
        {gen, get_parent, 0},
        {gen, get_proc_name, 1},
        {gen, name, 1},
        {gen, unregister_name, 1},
        {gen_event, start, 2},
        {gen_event, start_link, 2},
        {gen_event, start_monitor, 0},
        {gen_event, start_monitor, 1},
        {gen_event, start_monitor, 2},
        {gen_server, start_monitor, 3},
        {gen_server, start_monitor, 4},
        {http_uri, parse, 1},
        {http_uri, parse, 2},
        {http_uri, scheme_defaults, 0},
        {httpd_util, flatlength, 1},
        {httpd_util, integer_to_hexlist, 1},
        {httpd_util, strip, 1},
        {httpd_util, suffix, 1},
        {inet, info, 1},
        {inet, ipv4_mapped_ipv6_address, 1},
        {io_lib, format, 3},
        {io_lib, fwrite, 3},
        {io_lib, limit_term, 2},
        {io_lib, write_atom_as_latin1, 1},
        {json, decode, 1},
        {json, decode, 3},
        {json, decode_continue, 2},
        {json, decode_start, 3},
        {json, encode, 1},
        {json, encode, 2},
        {json, encode_atom, 2},
        {json, encode_binary, 1},
        {json, encode_binary_escape_all, 1},
        {json, encode_float, 1},
        {json, encode_list, 2},
        {json, encode_key_value_list, 2},
        {json, encode_key_value_list_checked, 2},
        {json, encode_map, 2},
        {json, encode_map_checked, 2},
        {json, encode_value, 2},
        {lib, error_message, 2},
        {lib, flush_receive, 0},
        {lib, nonl, 1},
        {lib, progname, 0},
        {lib, send, 2},
        {lib, sendw, 2},
        {lists, enumerate, 1},
        {lists, enumerate, 2},
        {lists, enumerate, 3},
        {lists, join, 2},
        {lists, search, 2},
        {lists, uniq, 1},
        {lists, uniq, 2},
        {lists, zip, 3},
        {lists, zip3, 4},
        {lists, zipwith, 4},
        {lists, zipwith3, 5},
        {maps, filtermap, 2},
        {maps, foreach, 2},
        {maps, from_keys, 2},
        {maps, groups_from_list, 2},
        {maps, groups_from_list, 3},
        {maps, intersect, 2},
        {maps, intersect_with, 3},
        {maps, iterator, 1},
        {maps, merge_with, 3},
        {maps, next, 1},
        {maps, take, 2},
        {maps, update_with, 3},
        {maps, update_with, 4},
        {math, ceil, 1},
        {math, floor, 1},
        {math, tau, 0},
        {math, fmod, 2},
        {net_kernel, start, 2},
        {orddict, foreach, 2},
        {orddict, take, 2},
        {ordsets, filtermap, 2},
        {ordsets, foreach, 2},
        {ordsets, is_empty, 1},
        {ordsets, is_equal, 2},
        {ordsets, map, 2},
        {os, cmd, 2},
        {os, env, 0}, % OTP 24.0
        {os, list_env_vars, 0},
        {peer, call, 4}, % OTP 25.0
        {peer, call, 5}, % OTP 25.0
        {peer, cast, 4}, % OTP 25.0
        {peer, get_state, 1}, % OTP 25.0
        {peer, random_name, 0}, % OTP 25.0
        {peer, random_name, 1}, % OTP 25.0
        {peer, send, 3}, % OTP 25.0
        {peer, start, 1}, % OTP 25.0
        {peer, start_link, 0}, % OTP 25.0
        {peer, start_link, 1}, % OTP 25.0
        {peer, stop, 1}, % OTP 25.0
        {pg2, create, 1}, % OTP < 24.0
        {pg2, delete, 1}, % OTP < 24.0
        {pg2, get_closest_pid, 1}, % OTP < 24.0
        {pg2, get_local_members, 1}, % OTP < 24.0
        {pg2, get_members, 1}, % OTP < 24.0
        {pg2, init, 1}, % OTP < 24.0
        {pg2, join, 2}, % OTP < 24.0
        {pg2, leave, 2}, % OTP < 24.0
        {pg2, start, 0}, % OTP < 24.0
        {pg2, start_link, 0}, % OTP < 24.0
        {pg2, which_groups, 0}, % OTP < 24.0
        {proc_lib, init_fail, 2},
        {proc_lib, init_fail, 3},
        {proc_lib, start_monitor, 3},
        {proc_lib, start_monitor, 4},
        {proc_lib, start_monitor, 5},
        {proplists, to_map, 1},
        {proplists, to_map, 2},
        {queue, all, 2},
        {queue, any, 2},
        {queue, delete, 2},
        {queue, delete_r, 2},
        {queue, delete_with, 2},
        {queue, delete_with_r, 2},
        {queue, filtermap, 2},
        {queue, foreach, 2},
        {queue, fold, 3},
        {rand, bytes, 1},
        {rand, bytes_s, 2},
        {rand, exsp_jump, 1},
        {rand, exsp_next, 1},
        {rand, jump, 0},
        {rand, jump, 1},
        {rand, mwc59, 1},
        {rand, mwc59_float, 1},
        {rand, mwc59_seed, 0},
        {rand, mwc59_seed, 1},
        {rand, mwc59_value, 1},
        {rand, mwc59_value32, 1},
        {rand, normal, 2},
        {rand, normal_s, 3},
        {rand, splitmix64_next, 1},
        {rand, uniform_real, 0},
        {rand, uniform_real_s, 1},
        {re, version, 0},
        {sets, filtermap, 2},
        {sets, foreach, 2},
        {sets, from_list, 2},
        {sets, is_equal, 2},
        {sets, is_empty, 1},
        {sets, map, 2},
        {sets, new, 1},
        {shell_docs, module_info, 0},
        {shell_docs, render, 5},
        {shell_docs, render_callback, 5},
        {snmpa, old_info_format, 1},
        {ssl, cipher_suites, 0},
        {ssl, cipher_suites, 1},
        {ssl, handshake, 1},
        {ssl, handshake, 2},
        {ssl, handshake, 3},
        {ssl, prf, 5},
        {ssl, ssl_accept, 1},
        {ssl, ssl_accept, 2},
        {ssl, ssl_accept, 3},
        {string, casefold, 1},
        {string, chomp, 1},
        {string, equal, 3},
        {string, equal, 4},
        {string, find, 2},
        {string, find, 3},
        {string, is_empty, 1},
        {string, jaro_similarity, 2},
        {string, length, 1},
        {string, lexemes, 2},
        {string, list_to_float, 1},
        {string, list_to_integer, 1},
        {string, lowercase, 1},
        {string, next_codepoint, 1},
        {string, next_grapheme, 1},
        {string, nth_lexeme, 3},
        {string, pad, 2},
        {string, pad, 3},
        {string, pad, 4},
        {string, prefix, 2},
        {string, replace, 3},
        {string, replace, 4},
        {string, reverse, 1},
        {string, slice, 2},
        {string, slice, 3},
        {string, split, 2},
        {string, split, 3},
        {string, take, 2},
        {string, take, 3},
        {string, take, 4},
        {string, titlecase, 1},
        {string, to_graphemes, 1},
        {string, trim, 1},
        {string, trim, 2},
        {string, trim, 3},
        {string, uppercase, 1},
        {supervisor, check_childspecs, 2},
        {supervisor, format_status, 2},
        {sys, get_log, 1},
        {timer, apply_after, 2},
        {timer, apply_after, 3},
        {timer, apply_interval, 2},
        {timer, apply_interval, 3},
        {timer, tc, 4},
        {unicode, characters_to_nfc_binary, 1},
        {unicode, characters_to_nfc_list, 1},
        {unicode, characters_to_nfd_binary, 1},
        {unicode, characters_to_nfd_list, 1},
        {unicode, characters_to_nfkc_binary, 1},
        {unicode, characters_to_nfkc_list, 1},
        {unicode, characters_to_nfkd_binary, 1},
        {unicode, characters_to_nfkd_list, 1},
        {unicode_util, casefold, 1},
        {unicode_util, cp, 1},
        {unicode_util, gc, 1},
        {unicode_util, get_case, 1},
        {unicode_util, is_whitespace, 1},
        {unicode_util, lookup, 1},
        {unicode_util, lowercase, 1},
        {unicode_util, nfc, 1},
        {unicode_util, nfd, 1},
        {unicode_util, nfkc, 1},
        {unicode_util, nfkd, 1},
        {unicode_util, spec_version, 0},
        {unicode_util, titlecase, 1},
        {unicode_util, uppercase, 1},
        {unicode_util, whitespace, 0},
        {uri_string, allowed_characters, 0},
        {uri_string, compose_query, 1},
        {uri_string, compose_query, 2},
        {uri_string, dissect_query, 1},
        {uri_string, is_host, 1},
        {uri_string, is_path, 1},
        {uri_string, normalize, 1},
        {uri_string, normalize, 2},
        {uri_string, parse, 1},
        {uri_string, percent_decode, 1},
        {uri_string, quote, 1},
        {uri_string, quote, 2},
        {uri_string, recompose, 1},
        {uri_string, resolve, 2},
        {uri_string, resolve, 3},
        {uri_string, transcode, 2},
        {uri_string, unquote, 1},
        {user, interfaces, 1},
        {xmerl_xml_indent, '#element#', 5},
        {xmerl_xml_indent, '#root#', 4},
        {zlib, adler32, 2},
        {zlib, adler32, 3},
        {zlib, adler32_combine, 4},
        {zlib, crc32, 2},
        {zlib, crc32, 3},
        {zlib, crc32_combine, 4},
        {zlib, getBufSize, 1},
        {zlib, inflate, 3},
        {zlib, inflateChunk, 1},
        {zlib, inflateChunk, 2},
        {zlib, inflateGetDictionary, 1},
        {zlib, safeInflate, 2},
        {zlib, setBufSize, 2},
        {zlib, compress, 2},
        {zlib, gzip, 2},
        {zlib, zip, 2}],

Behaviours = [gen_statem],

OTPRelease = list_to_integer(erlang:system_info(otp_release)),

ErlOpts = case lists:keyfind(erl_opts, 1, CONFIG) of
              {_, EO} -> EO;
              _ -> []
          end,

SrcDirs = case lists:keyfind(src_dirs, 1, ErlOpts) of
              {_, [_|_] = SD} -> SD;
              _ -> ["src"]
          end,

lists:keystore(erl_opts, 1,
               if
                   OTPRelease >= 23 ->
                       case lists:keyfind(xref_checks, 1, CONFIG) of
                           {_, [_|_] = XRef} ->
                               lists:keystore(xref_checks, 1, CONFIG,
                                              {xref_checks, XRef -- [deprecated_function_calls, deprecated_functions]});
                           _ -> CONFIG
                       end;
                   true -> CONFIG
               end,
               {erl_opts,
                lists:keystore(src_dirs, 1, ErlOpts, {src_dirs, case code:which(pg) of
                                                                    non_existing -> SrcDirs ++ ["src_ext"];
                                                                    _ -> SrcDirs -- ["src_ext"]
                                                                end}) ++
                try erlang:convert_time_unit(1, second, second) of
                    _ -> [{d, 'HAVE_NEW_TIME_UNITS'}]
                catch
                    _:_ -> []
                end ++
                lists:map(fun(E) ->
                              {d, list_to_atom(lists:flatten(io_lib:format("HAVE_~s__~s_~B",
                                                                           case E of
                                                                               {M, F, A} -> [M, F, A];
                                                                               {F, A} -> [erlang, F, A]
                                                                           end)))}
                          end, lists:filter(Check, BIFs ++ Funs)) ++
                lists:filtermap(fun(E) ->
                                    try E:module_info(exports) of
                                        Exports ->
                                            lists:member({behaviour_info, 1}, Exports) andalso
                                                {true, {d, list_to_atom(lists:concat(["HAVE_BEHAVIOUR_", E]))}}
                                    catch
                                        _:_ -> false
                                    end
                                end, Behaviours)}) ++
if
    OTPRelease >= 20 -> [];
    true -> [{pre_hooks, [{compile, "make -s -C src/uc_spec otpbp_unicode_util.erl"}]},
             {post_hooks, [{clean, "rm -f src/uc_spec/*.erl"}]}]
end.
