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},
        {error, 3},
        {spawn_request_abandon, 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},
        {binary, join, 2},
        {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},
        {calendar, local_time_to_system_time, 1},
        {calendar, local_time_to_system_time, 2},
        {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},
        {calendar, universal_time_to_system_time, 1},
        {calendar, universal_time_to_system_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, module_status, 0},
        {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, start, 0},
        {crypto, stop, 0},
        {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},
        {disk_log, accessible_logs, 0},
        {disk_log, lclose, 2},
        {disk_log_server, all, 0},
        {disksup, get_disk_info, 0},
        {disksup, get_disk_info, 1},
        {disksup, parse_df, 2},
        {eldap, paged_result_control, 1},
        {eldap, paged_result_control, 2},
        {eldap, paged_result_cookie, 1},
        {erl_anno, set_end_location, 2},
        {erl_epmd, listen_port_please, 2},
        {erl_epmd, port_please, 2},
        {erl_epmd, port_please, 3},
        {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_pp, legalize_vars, 1},
        {erlang, get_stacktrace, 0},
        {erlang, get_cookie, 1},
        {erlang, processes_iterator, 0},
        {erlang, processes_next, 1},
        {erlang, set_cookie, 1},
        {erpc, check_response, 3},
        {erpc, receive_response, 3},
        {erpc, reqids_add, 3},
        {erpc, reqids_size, 1},
        {erpc, reqids_to_list, 1},
        {erpc, send_request, 6},
        {erpc, wait_response, 3},
        {erts_internal, binary_to_integer, 2},
        {erts_internal, list_to_integer, 2},
        {erts_internal, map_next, 3},
        {erts_internal, processes_next, 1},
        {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, safe_relative_path, 2},
        {gb_sets, filtermap, 2},
        {gb_sets, foreach, 2},
        {gb_sets, is_equal, 2},
        {gb_sets, map, 2},
        {gb_trees, foreach, 2},
        {gen, debug_options, 1},
        {gen_event, start_monitor, 0},
        {gen_event, start_monitor, 1},
        {gen_event, start_monitor, 2},
        {gen_sctp, connect, 3},
        {gen_sctp, connect_init, 3},
        {gen_server, start_monitor, 3},
        {gen_server, start_monitor, 4},
        {gen_tcp, connect, 2},
        {gen_udp, connect, 2},
        {gen_udp, send, 3},
        {gen_udp, send, 5},
        {http_uri, parse, 1},
        {http_uri, parse, 2},
        {http_uri, scheme_defaults, 0},
        {httpc, ssl_verify_host_options, 1},
        {httpd, serve, 1},
        {httpd, start, 1},
        {httpd_util, flatlength, 1},
        {httpd_util, integer_to_hexlist, 1},
        {httpd_util, strip, 1},
        {httpd_util, suffix, 1},
        {inet, ensure_sockaddr, 1},
        {inet, gen_tcp_module, 1},
        {inet, gen_udp_module, 1},
        {inet, info, 1},
        {inet, ipv4_mapped_ipv6_address, 1},
        {inet, is_ip_address, 1},
        {inet, is_ipv4_address, 1},
        {inet, is_ipv6_address, 1},
        {io_lib, bformat, 2},
        {io_lib, bformat, 3},
        {io_lib, bfwrite, 2},
        {io_lib, bfwrite, 3},
        {io_lib, bwrite, 1},
        {io_lib, bwrite, 2},
        {io_lib, bwrite_string, 2},
        {io_lib, bwrite_string, 3},
        {io_lib, format, 3},
        {io_lib, fwrite, 3},
        {io_lib, write, 5},
        {io_lib, write_bin, 5},
        {io_lib, write_string_bin, 3},
        {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},
        {json, format, 1},
        {json, format, 2},
        {json, format, 3},
        {json, format_key_value_list, 3},
        {json, format_key_value_list_checked, 3},
        {json, format_value, 3},
        {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, search, 2},
        {lists, uniq, 1},
        {lists, uniq, 2},
        {lists, zip, 3},
        {lists, zip3, 4},
        {lists, zipwith, 4},
        {lists, zipwith3, 5},
        {logger, get_config, 0},
        {logger, get_handler_config, 0},
        {logger, i, 0},
        {logger, i, 2},
        {logger, reconfigure, 0},
        {logger, set_application_level, 2},
        {logger, set_module_level, 2},
        {logger, timestamp, 0},
        {logger, unset_application_level, 1},
        {logger, unset_module_level, 1},
        {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},
        {math, tau, 0},
        {net_kernel, start, 2},
        {orddict, foreach, 2},
        {ordsets, filtermap, 2},
        {ordsets, foreach, 2},
        {ordsets, is_empty, 1},
        {ordsets, is_equal, 2},
        {ordsets, map, 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
        {persistent_term, erase, 1},
        {persistent_term, get, 1},
        {persistent_term, get, 2},
        {persistent_term, put, 2},
        {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
        {prim_socket, enc_sockaddr, 1},
        {proc_lib, get_label, 1},
        {proc_lib, init_fail, 2},
        {proc_lib, init_fail, 3},
        {proc_lib, set_label, 1},
        {proc_lib, start_monitor, 3},
        {proc_lib, start_monitor, 4},
        {proc_lib, start_monitor, 5},
        {proplists, to_map, 1},
        {proplists, to_map, 2},
        {pubkey_cert, subject_id, 1},
        {pubkey_ocsp, otp_cert, 1},
        {pubkey_os_cacerts, clear, 0},
        {pubkey_os_cacerts, format_error, 2},
        {pubkey_os_cacerts, get, 0},
        {pubkey_os_cacerts, load, 0},
        {pubkey_os_cacerts, load, 1},
        {pubkey_ssh, decode, 2},
        {pubkey_ssh, encode, 2},
        {pubkey_ssh, new_openssh_decode, 1},
        {pubkey_ssh, new_openssh_encode, 1},
        {pubkey_ssh, pad, 2},
        {public_key, cacerts_clear, 0},
        {public_key, cacerts_get, 0},
        {public_key, cacerts_load, 0},
        {public_key, cacerts_load, 1},
        {public_key, encrypt_private, 3},
        {public_key, encrypt_public, 3},
        {public_key, pkix_hash_type, 1},
        {public_key, pkix_subject_id, 1},
        {public_key, pkix_verify_hostname_match_fun, 1},
        {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, mwc59, 1},
        {rand, mwc59_float, 1},
        {rand, mwc59_seed, 0},
        {rand, mwc59_seed, 1},
        {rand, mwc59_value, 1},
        {rand, mwc59_value32, 1},
        {rand, splitmix64_next, 1},
        {rand, uniform_real, 0},
        {rand, uniform_real_s, 1},
        {scheduler, get_sample, 0},
        {scheduler, get_sample_all, 0},
        {scheduler, sample, 0},
        {scheduler, sample_all, 0},
        {scheduler, utilization, 1},
        {scheduler, utilization, 2},
        {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},
        {ssh_file, decode, 2},
        {ssh_file, encode, 2},
        {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, jaro_similarity, 2},
        {supervisor, check_childspecs, 2},
        {sys, get_log, 1},
        {timer, apply_after, 2},
        {timer, apply_after, 3},
        {timer, apply_interval, 2},
        {timer, apply_interval, 3},
        {timer, tc, 4},
        {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, inflateChunk, 1},
        {zlib, inflateChunk, 2},
        {zlib, setBufSize, 2},
        {zlib, compress, 2},
        {zlib, gzip, 2},
        {zlib, zip, 2}],

Behaviours = [],

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}) ++
                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)}).
