#!env perl
use
POSIX
qw/EXIT_SUCCESS/
;
autoflush STDOUT 1;
my
$version
= get_version();
print
"Generating config for tconv version $version\n"
;
my
$config_h_in
= File::Spec->catfile(
'include'
,
'tconv_config.h.in'
);
my
$config_h
= File::Spec->catfile(
'output'
,
'include'
,
'tconv_config.h'
);
make_path(dirname(
$config_h
));
my
$ac
= Config::AutoConf::INI->new(
logfile
=>
'config.log'
);
$ac
->define_var(
'TCONV_NTRACE'
, 1);
$ac
->check;
write_tconv_config(
$version
,
$config_h_in
,
$config_h
);
my
$export_h
= File::Spec->catfile(
'output'
,
'include'
,
'tconv'
,
'export.h'
);
make_path(dirname(
$export_h
));
open
(
my
$fh
,
'>'
,
$export_h
) ||
die
"Cannot open $export_h, $!"
;
print
$fh
"#define tconv_EXPORT\n"
;
print
$fh
"#define TCONV_NO_EXPORT\n"
;
close
(
$fh
) ||
warn
"Cannot close $export_h, $!"
;
my
@additional_includes
= ();
my
@additional_srcdir
= ();
my
$extra_compiler_flags
=
''
;
{
my
$tar
=Archive::Tar->new();
my
$libiconv_tar
= File::Spec->catfile(
'3rdparty'
,
'tar'
,
'libiconv-1.15.tar.gz'
);
$tar
->
read
(
$libiconv_tar
);
print
"... Extracting $libiconv_tar in 3rdparty/output\n"
;
make_path(File::Spec->catdir(
'3rdparty'
,
'output'
));
{
local
$CWD
= File::Spec->catdir(
'3rdparty'
,
'output'
);
$tar
->extract();
}
undef
$tar
;
find(
{
no_chdir
=> 1,
wanted
=>
sub
{
my
$file
= File::Spec->canonpath(
$_
);
if
(-f
$file
&& (
$file
=~ /\.c$/ ||
$file
=~ /\.h$/)) {
open
(
my
$in
,
'<'
,
$file
) ||
die
"Failed to open $file, $!"
;
my
$content
=
do
{
local
$/; <
$in
>; };
close
(
$in
) ||
warn
"Failed to close $file, $!"
;
my
$orig
=
$content
;
$content
=~ s/
"config\.h"
/
"iconv_config.h"
/g;
$content
=~ s/<config\.h>/<iconv_config.h>/g;
if
(
$orig
ne
$content
) {
open
(
my
$out
,
'>'
,
$file
) ||
die
"Failed to open $file, $!"
;
print
$out
$content
;
close
(
$out
) ||
warn
"Failed to close $file, $!"
;
print
STDERR
"... Replaced config.h by iconv_config.h in $file\n"
;
}
}
},
},
File::Spec->catdir(
'3rdparty'
,
'output'
,
'libiconv-1.15'
));
my
$config_h
= File::Spec->catfile(
'3rdparty'
,
'output'
,
'libiconv-1.15'
,
'include'
,
'iconv_config.h'
);
print
"... Generate file $config_h\n"
;
open
(
my
$fd
,
'>'
,
$config_h
) ||
die
"Failed to open $config_h, $!"
;
print
$fd
"
/* Generated file */
/* localcharset.c will play itself
with
WIN32_LEAN_AND_MEAN... */
\n";
close
(
$fd
) ||
warn
"Failed to close $config_h, $!"
;
my
$iconv_h_in
= File::Spec->catfile(
'3rdparty'
,
'output'
,
'libiconv-1.15'
,
'include'
,
'iconv.h.in'
);
my
$iconv_h
= File::Spec->catfile(
'3rdparty'
,
'output'
,
'libiconv-1.15'
,
'include'
,
'iconv.h'
);
print
"... Generate file $iconv_h\n"
;
write_iconv_h(
$iconv_h_in
,
$iconv_h
);
my
$localcharset_h_in
= File::Spec->catfile(
'3rdparty'
,
'output'
,
'libiconv-1.15'
,
'libcharset'
,
'include'
,
'localcharset.h.in'
);
my
$localcharset_h
= File::Spec->catfile(
'3rdparty'
,
'output'
,
'libiconv-1.15'
,
'libcharset'
,
'include'
,
'localcharset.h'
);
print
"... Generate file $localcharset_h\n"
;
write_localcharset_h(
$localcharset_h_in
,
$localcharset_h
);
print
"... Checking for nl_langinfo(CODESET)\n"
;
$extra_compiler_flags
.=
" -DHAVE_LANGINFO_CODESET"
if
get_have_langinfo_codeset();
my
$have_decl_getc_unlocked
;
$ac
->check_func(
'getc_unlocked'
, {
action_on_false
=>
sub
{
$have_decl_getc_unlocked
= 0 },
action_on_true
=>
sub
{
$have_decl_getc_unlocked
= 1 } } );
$extra_compiler_flags
.=
" -DHAVE_DECL_GETC_UNLOCK"
if
$have_decl_getc_unlocked
;
print
"... Checking for endianness\n"
;
$extra_compiler_flags
.=
" -DWORDS_LITTLEENDIAN"
unless
get_is_big_endian();
$extra_compiler_flags
.=
" -DICONV_CONST="
;
$extra_compiler_flags
.=
" -DLIBDIR=\\\"\\\""
;
$extra_compiler_flags
.=
" -DHAVE_WORKING_O_NOFOLLOW=0"
;
$extra_compiler_flags
.=
" -DENABLE_EXTRA"
;
push
(
@additional_srcdir
, File::Spec->catfile(
'3rdparty'
,
'output'
,
'libiconv-1.15'
,
'libcharset'
,
'lib'
,
'localcharset.c'
));
push
(
@additional_srcdir
, File::Spec->catfile(
'3rdparty'
,
'output'
,
'libiconv-1.15'
,
'lib'
,
'relocatable.c'
));
push
(
@additional_srcdir
, File::Spec->catfile(
'3rdparty'
,
'output'
,
'libiconv-1.15'
,
'lib'
,
'iconv.c'
));
push
(
@additional_includes
, File::Spec->catfile(
'3rdparty'
,
'output'
,
'libiconv-1.15'
,
'include'
));
push
(
@additional_includes
, File::Spec->catfile(
'3rdparty'
,
'output'
,
'libiconv-1.15'
,
'libcharset'
,
'include'
));
}
{
my
$tar
=Archive::Tar->new();
my
$cchardet_tar
= File::Spec->catfile(
'3rdparty'
,
'tar'
,
'cchardet-1.0.0.tar.gz'
);
$tar
->
read
(
$cchardet_tar
);
print
"... Extracting $cchardet_tar in 3rdparty/output\n"
;
make_path(File::Spec->catdir(
'3rdparty'
,
'output'
));
{
local
$CWD
= File::Spec->catdir(
'3rdparty'
,
'output'
);
$tar
->extract();
}
undef
$tar
;
my
$libcharsetdetect
= File::Spec->catdir(
'3rdparty'
,
'output'
,
'cchardet-1.0.0'
,
'src'
,
'ext'
,
'libcharsetdetect'
);
my
$nspremu
= File::Spec->catdir(
$libcharsetdetect
,
'nspr-emu'
);
print
"... Suppress directory $nspremu\n"
;
remove_tree(
$nspremu
);
print
"... Generate directory $nspremu\n"
;
make_path(
$nspremu
);
my
$nsDebug
= File::Spec->catfile(
$nspremu
,
'nsDebug.h'
);
print
"... Generate file $nsDebug\n"
;
copy(File::Spec->catfile(
'include'
,
'nsDebug.h.in'
),
$nsDebug
);
my
$prmem
= File::Spec->catfile(
$nspremu
,
'prmem.h'
);
print
"... Generate file $prmem\n"
;
copy(File::Spec->catfile(
'include'
,
'prmem.h.in'
),
$prmem
);
my
$nscore
= File::Spec->catfile(
$libcharsetdetect
,
'nscore.h'
);
print
"... Suppress file $nscore\n"
;
unlink
(
$nscore
);
print
"... Generate file $nscore\n"
;
write_nscore(File::Spec->catfile(
'include'
,
'nscore.h.in'
),
$nscore
);
push
(
@additional_srcdir
, File::Spec->catdir(
'3rdparty'
,
'output'
,
'cchardet-1.0.0'
,
'src'
,
'ext'
,
'libcharsetdetect'
,
'mozilla'
,
'extensions'
,
'universalchardet'
,
'src'
,
'base'
));
push
(
@additional_srcdir
, File::Spec->catfile(
$libcharsetdetect
,
'charsetdetect.cpp'
));
push
(
@additional_includes
, File::Spec->catdir(
$libcharsetdetect
,
'mozilla'
,
'extensions'
,
'universalchardet'
,
'src'
,
'base'
));
push
(
@additional_includes
, File::Spec->catdir(
$libcharsetdetect
,
'nspr-emu'
));
push
(
@additional_includes
,
$libcharsetdetect
);
}
my
@additional
= ();
if
(is_os_type(
'Windows'
)) {
push
(
@additional
,
'dlfcn-win32'
);
push
(
@additional_srcdir
, File::Spec->catdir(
'output'
,
'3rdparty'
,
'dlfcn-win32'
,
'dlfcn.c'
));
push
(
@additional_includes
, File::Spec->catdir(
'output'
,
'3rdparty'
,
'dlfcn-win32'
));
}
foreach
(
qw/genericLogger/
,
@additional
) {
if
(! dircopy(File::Spec->catdir(
'3rdparty'
,
'github'
,
$_
),
File::Spec->catdir(
'output'
,
'3rdparty'
,
$_
))) {
die
"Failed to copy $_"
;
}
print
"... Copying $_\n"
;
my
$CMakeObjects
= File::Spec->catfile(
'output'
,
'3rdparty'
,
$_
,
'CMakeObjects.PL'
);
if
(-e
$CMakeObjects
) {
print
"... Executing $CMakeObjects\n"
;
my
$in
;
my
$out
;
my
$err
;
{
local
$CWD
= dirname(
$CMakeObjects
);
run([$^X, basename(
$CMakeObjects
)], \
$in
, \
$out
, \
$err
) ||
die
"Failed to execute $CMakeObjects"
. (
$err
?
"\n$err"
:
''
);
}
if
(
$out
) {
foreach
(
grep
{
defined
}
split
(/\R/,
$out
)) {
print
"... ... $_\n"
;
}
}
my
$inc
= File::Spec->catdir(
'output'
,
'3rdparty'
,
$_
,
'output'
,
'include'
);
push
(
@additional_includes
,
$inc
)
if
(-d
$inc
);
}
my
$inc
= File::Spec->catdir(
'output'
,
'3rdparty'
,
$_
,
'include'
);
push
(
@additional_includes
,
$inc
)
if
(-d
$inc
);
}
$ac
->write_config_h(File::Spec->catfile(
'output'
,
'include'
,
'tconv'
,
'config_autoconf.h'
));
my
@sources
;
find(
{
no_chdir
=> 1,
wanted
=>
sub
{
my
$file
= File::Spec->canonpath(
$_
);
if
(-f
$file
&& (
$file
=~ /\.c$/ ||
$file
=~ /\.cpp$/)) {
my
$bfile
= basename(
$file
);
if
(! (
$file
=~ /ICU\.c$/)) {
push
(
@sources
,
$file
)
}
}
},
},
'src'
,
@additional_srcdir
);
my
$cbuilder
= ExtUtils::CBuilder->new();
my
@objects
;
my
$obj_dir
= File::Spec->catfile(
'output'
,
'obj4perl'
);
make_path(
$obj_dir
);
foreach
my
$source
(
@sources
) {
my
$is_cplusplus
= (
$source
=~ /\.cpp$/i ||
$source
=~ /\.c\+\+$/i);
my
$obj
= File::Spec->catfile(
$obj_dir
, basename(
$cbuilder
->object_file(
$source
)));
push
(
@objects
,
$cbuilder
->object_file(
$source
));
$cbuilder
->compile(
source
=>
$source
,
extra_compiler_flags
=>
$extra_compiler_flags
,
object_file
=>
$obj
,
include_dirs
=> [
'include'
, File::Spec->catdir(
'output'
,
'include'
),
@additional_includes
],
'C++'
=>
$is_cplusplus
);
}
exit
(EXIT_SUCCESS);
sub
get_version {
open
(
my
$fh
,
'<'
,
'CMakeLists.txt'
) ||
die
"Cannot open CMakeLists.txt, $!"
;
my
$content
=
do
{
local
$/; <
$fh
>; };
close
(
$fh
) ||
warn
"Failed to close CMakeLists.txt, $!"
;
my
@rc
;
if
(
$content
=~ /^MYPACKAGESTART\s*\(\s
*tconv
\s+(\d+)\s+(\d+)\s+(\d+)\s*\)/sm) {
@rc
= ($1, $2, $3);
}
else
{
foreach
(
qw/TCONV_VERSION_MAJOR TCONV_VERSION_MINOR TCONV_VERSION_PATCH/
) {
if
(
$content
=~ /^SET\s*\(\s
*$_
\s*(\d+)\s*\)/sm) {
push
(
@rc
, $1);
}
else
{
die
"Failed to find $_"
,
}
}
}
return
join
(
'.'
,
@rc
)
}
sub
write_tconv_config {
my
(
$version
,
$input
,
$output
) =
@_
;
make_path(dirname(
$output
));
open
(
my
$fh
,
'<'
,
$input
) ||
die
"Cannot open $input, $!"
;
my
$source
=
do
{
local
$/; <
$fh
>; };
close
(
$fh
) ||
warn
"Cannot close $input, $!"
;
$source
=~ s/^[ \t]*
open
(
$fh
,
'>'
,
$output
) ||
die
"Cannot open $output, $!"
;
print
$fh
<<CONFIG;
#ifndef TCONV_CONFIG_WRAPPER_H
#define TCONV_CONFIG_WRAPPER_H
#include <tconv/config_autoconf.h>
#define TCONV_C_INLINE
#define TCONV_HAVE_ICONV 1
#define TCONV_VERSION "$version"
$source
#endif /* TCONV_CONFIG_WRAPPER_H */
CONFIG
close
(
$fh
) ||
warn
"Cannot close $output, $!"
;
}
sub
write_nscore {
my
(
$input
,
$output
) =
@_
;
make_path(dirname(
$output
));
open
(
my
$fh
,
'<'
,
$input
) ||
die
"Cannot open $input, $!"
;
my
$source
=
do
{
local
$/; <
$fh
>; };
close
(
$fh
) ||
warn
"Cannot close $input, $!"
;
$source
=~ s/^[ \t]*
$source
=~ s/^[ \t]*
open
(
$fh
,
'>'
,
$output
) ||
die
"Cannot open $output, $!"
;
print
$fh
<<NSCORE;
#ifndef NSCORE_WRAPPER_H
#define NSCORE_WRAPPER_H
#include <tconv/config_autoconf.h>
$source
#endif /* TCONV_CONFIG_WRAPPER_H */
NSCORE
close
(
$fh
) ||
warn
"Cannot close $output, $!"
;
}
sub
write_iconv_h {
my
(
$input
,
$output
) =
@_
;
make_path(dirname(
$output
));
open
(
my
$fh
,
'<'
,
$input
) ||
die
"Cannot open $input, $!"
;
my
$source
=
do
{
local
$/; <
$fh
>; };
close
(
$fh
) ||
warn
"Cannot close $input, $!"
;
$source
=~ s/\
@DLL_VARIABLE
\@//smg;
$source
=~ s/\
@EILSEQ
\@/134679/smg;
$source
=~ s/\
@ICONV_CONST
\@//smg;
$source
=~ s/\
@USE_MBSTATE_T
\@/0/smg;
$source
=~ s/\
@HAVE_WCHAR_T
\@/0/smg;
open
(
$fh
,
'>'
,
$output
) ||
die
"Cannot open $output, $!"
;
print
$fh
$source
;
close
(
$fh
) ||
warn
"Cannot close $output, $!"
;
}
sub
write_localcharset_h {
my
(
$input
,
$output
) =
@_
;
make_path(dirname(
$output
));
open
(
my
$fh
,
'<'
,
$input
) ||
die
"Cannot open $input, $!"
;
my
$source
=
do
{
local
$/; <
$fh
>; };
close
(
$fh
) ||
warn
"Cannot close $input, $!"
;
open
(
$fh
,
'>'
,
$output
) ||
die
"Cannot open $output, $!"
;
print
$fh
$source
;
close
(
$fh
) ||
warn
"Cannot close $output, $!"
;
}
sub
get_have_langinfo_codeset {
my
$source
.=
q'
#include <stdlib.h>
#include <langinfo.h>
int main(int ac, char **av)
{
char *cs = nl_langinfo(CODESET);
exit(0);
}'
;
my
$rc
=
eval
{
my
$cbuilder
= ExtUtils::CBuilder->new();
my
(
$fh
,
$filename
) = tempfile(
SUFFIX
=>
'.c'
,
UNLINK
=> 0);
print
$fh
$source
;
close
(
$fh
) ||
warn
"Cannot close $filename, $!"
;
my
$obj
=
$cbuilder
->object_file(
$filename
);
$cbuilder
->compile(
source
=>
$filename
,
object_file
=>
$obj
,
'C++'
=> 0
);
$cbuilder
->link_executable(
module_name
=>
'ICONV::TEST'
,
objects
=>
$obj
);
system
(
$cbuilder
->exe_file(
$obj
),
'unused'
,
'parameter'
);
my
$exitcode
= $? >> 8;
unlink
$cbuilder
->exe_file(
$obj
);
unlink
$obj
;
unlink
$filename
;
$exitcode
? 0 : 1;
} // 0;
print
$@
if
$@;
return
$rc
;
}
sub
get_is_big_endian {
my
$source
.=
q'
#include <stdlib.h>
const int i = 1;
#define is_bigendian() ( (*(char*)&i) == 0 )
int main(int ac, char **av)
{
exit(is_bigendian() ? 0 : 1);
}'
;
my
$cbuilder
= ExtUtils::CBuilder->new();
my
(
$fh
,
$filename
) = tempfile(
SUFFIX
=>
'.c'
,
UNLINK
=> 0);
print
$fh
$source
;
close
(
$fh
) ||
warn
"Cannot close $filename, $!"
;
my
$obj
=
$cbuilder
->object_file(
$filename
);
$cbuilder
->compile(
source
=>
$filename
,
object_file
=>
$obj
,
'C++'
=> 0
);
$cbuilder
->link_executable(
module_name
=>
'ICONV::TEST'
,
objects
=>
$obj
);
system
(
$cbuilder
->exe_file(
$obj
),
'unused'
,
'parameter'
);
my
$exitcode
= $? >> 8;
unlink
$cbuilder
->exe_file(
$obj
);
unlink
$obj
;
my
$rc
=
$exitcode
? 0 : 1;
unlink
$filename
;
return
$rc
;
}