#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import shutil
import glob
from conans import ConanFile, AutoToolsBuildEnvironment, tools, VisualStudioBuildEnvironment
from conans.errors import ConanInvalidConfiguration
class ncursesConan(ConanFile):
name = "ncurses"
version = "6.1"
url = "https://github.com/conan-community/conan-ncurses"
homepage = "https://www.gnu.org/software/ncurses"
author = "Conan Community"
license = "X11"
description = "An API, allowing the programmer to write text-based user interfaces, TUIs, " \
"in a terminal-independent manner"
topics = ("conan", "ncurses", "terminal", "screen", "tui")
settings = "os", "compiler", "arch", "build_type"
options = {"shared": [True, False], "fPIC": [True, False], "with_cpp": [True, False],
"allow_msvc": [True, False], "allow_mingw": [True, False]}
default_options = {"shared": False, "fPIC": True, "with_cpp": True,
"allow_msvc": True, "allow_mingw": True}
exports = "LICENSE"
# NOTE: "compile" was patched: .cc files are properly handled with MinGW-style path conversion
exports_sources = ["ncurses.patch", "compile", "ar-lib"]
_autotools = None
_source_subfolder = "source_subfolder"
@property
def _is_msvc(self):
return self.settings.compiler == "Visual Studio"
@property
def _is_mingw_windows(self):
return self.settings.os == "Windows" and self.settings.compiler == "gcc" and os.name == "nt"
def config_options(self):
if self.settings.os == "Windows":
del self.options.fPIC
def requirements(self):
if self._is_msvc:
self.requires("getopt/1.0@bincrafters/stable")
self.requires("dirent-win32/1.23.2@bincrafters/stable")
def configure(self):
# FIXME (uilian): Fix Windows support
if self.settings.os == "Windows" and self.settings.compiler == "gcc" and not self.options.allow_mingw:
raise ConanInvalidConfiguration("Oops! ncurses is not supported on MinGW yet")
if self.settings.os == "Windows" and self.settings.compiler == "Visual Studio" and not self.options.allow_msvc:
raise ConanInvalidConfiguration("Oops! ncurses is not supported for Visual Studio yet")
if not self.options.with_cpp:
del self.settings.compiler.libcxx
def source(self):
folder_name = "ncurses-%s" % self.version
sha256 = "aa057eeeb4a14d470101eff4597d5833dcef5965331be3528c08d99cebaa0d17"
url = "https://invisible-mirror.net/archives/ncurses/%s.tar.gz" % folder_name
tools.get(url=url, sha256=sha256)
os.rename(folder_name, self._source_subfolder)
os.makedirs(os.path.join(self._source_subfolder, 'build-aux'))
shutil.move('compile', os.path.join(self._source_subfolder, 'build-aux', 'compile'))
shutil.move('ar-lib', os.path.join(self._source_subfolder, 'build-aux', 'ar-lib'))
def build_requirements(self):
if self._is_msvc or self._is_mingw_windows:
self.build_requires("msys2_installer/latest@bincrafters/stable")
def _patch_msvc_sources(self):
if self._is_msvc:
# TODO: this is a mess! please create patch file from this!
tools.replace_in_file("configure",
r"exec \$* ${LDFLAGS} -shared -Wl,--enable-auto-import,--out-implib=\${IMPORT_LIB} -Wl,--export-all-symbols -o \${SHARED_LIB}",
r"exec \$* ${LDFLAGS} -Xlinker -OUT:\${SHARED_LIB} -Xlinker -IMPLIB:\${IMPORT_LIB} -Xlinker -DLL -Xlinker -SUBSYSTEM:WINDOWS")
for lib in ["ncurses", "panel", "menu", "form", "c++"]:
tools.replace_in_file(os.path.join(lib, "Makefile.in"),
"-DHAVE_CONFIG_H",
"-DHAVE_CONFIG_H -D_BUILD_NCURSES_DLL")
tools.replace_in_file(os.path.join("panel", "panel.c"),
'#include "panel.priv.h"',
'#include "panel.priv.h"\n'
'NCURSES_EXPORT_VAR(SCREEN *) SP = NULL;')
tools.replace_in_file(os.path.join("c++", "cursesf.h"),
"# include <form.h>",
"# include <form.h>\n"
"__declspec(dllimport) FIELDTYPE * TYPE_ALPHA;\n"
"__declspec(dllimport) FIELDTYPE * TYPE_ALNUM;\n"
"__declspec(dllimport) FIELDTYPE * TYPE_ENUM;\n"
"__declspec(dllimport) FIELDTYPE * TYPE_INTEGER;\n"
"__declspec(dllimport) FIELDTYPE * TYPE_NUMERIC;\n"
"__declspec(dllimport) FIELDTYPE * TYPE_REGEXP;\n"
"__declspec(dllimport) FIELDTYPE * TYPE_IPV4;")
tools.replace_in_file(os.path.join("c++", "cursesw.h"),
"# include <curses.h>",
"# define acs_map acs_map_workaround\n"
"# include <curses.h>\n"
"# undef acs_map\n"
"__declspec(dllimport) int COLORS;\n"
"__declspec(dllimport) int COLOR_PAIRS;\n"
"__declspec(dllimport) unsigned acs_map[];")
tools.replace_in_file(os.path.join("menu", "m_global.c"),
'#include "menu.priv.h"',
'#include "menu.priv.h"\n'
'NCURSES_EXPORT_VAR(SCREEN *) SP = NULL;\n'
'NCURSES_EXPORT_VAR(WINDOW *) stdscr = 0;\n'
'NCURSES_EXPORT_VAR(WINDOW *) curscr = 0;\n'
'NCURSES_EXPORT_VAR(WINDOW *) newscr = 0;\n'
'NCURSES_EXPORT_VAR(int) LINES = 0;\n'
'NCURSES_EXPORT_VAR(int) COLS = 0;\n'
'NCURSES_EXPORT_VAR(int) TABSIZE = 8;')
tools.replace_in_file(os.path.join("form", "frm_data.c"),
'#include "form.priv.h"',
'#include "form.priv.h"\n'
'NCURSES_EXPORT_VAR(SCREEN *) SP = NULL;\n'
'NCURSES_EXPORT_VAR(WINDOW *) stdscr = 0;\n'
'NCURSES_EXPORT_VAR(WINDOW *) curscr = 0;\n'
'NCURSES_EXPORT_VAR(WINDOW *) newscr = 0;')
tools.replace_in_file(os.path.join("c++", "cursslk.cc"),
'#include "cursesapp.h"',
'#include "cursesapp.h"\n'
'NCURSES_EXPORT_VAR(WINDOW *) stdscr = 0;\n'
'NCURSES_EXPORT_VAR(WINDOW *) curscr = 0;\n'
'NCURSES_EXPORT_VAR(WINDOW *) newscr = 0;\n'
'NCURSES_EXPORT_VAR(int) LINES = 0;\n'
'NCURSES_EXPORT_VAR(int) COLS = 0;\n'
'NCURSES_EXPORT_VAR(int) TABSIZE = 8;')
tools.replace_in_file(os.path.join("c++", "cursslk.h"),
"static long NCURSES_IMPEXP count;",
"static long count;")
tools.replace_in_file(os.path.join("c++", "cursslk.h"),
"static Label_Layout NCURSES_IMPEXP format;",
"static Label_Layout format;")
tools.replace_in_file(os.path.join("c++", "cursslk.h"),
"static int NCURSES_IMPEXP num_labels;",
"static int num_labels;")
tools.replace_in_file(os.path.join("c++", "cursslk.h"),
"bool NCURSES_IMPEXP b_attrInit;",
"bool b_attrInit;")
tools.replace_in_file(os.path.join("c++", "cursslk.h"),
"NCURSES_IMPEXP Soft_Label_Key_Set();",
"Soft_Label_Key_Set();")
tools.replace_in_file(os.path.join("c++", "cursslk.h"),
"NCURSES_IMPEXP Soft_Label_Key& operator[](int i);",
"Soft_Label_Key& operator[](int i);")
tools.replace_in_file(os.path.join("ncurses", "tinfo", "make_hash.c"),
"#include <tinfo/doalloc.c>",
"#define _MAKE_HASH\n"
"#include <tinfo/doalloc.c>")
tools.replace_in_file(os.path.join("ncurses", "tinfo", "make_keys.c"),
"#include <names.c>",
"#define _MAKE_KEYS\n"
"#include <names.c>")
tools.replace_in_file(os.path.join("ncurses", "tinfo", "doalloc.c"),
"NCURSES_EXPORT(void *)",
"#ifdef _MAKE_HASH\n"
"void*\n"
"#else\n"
"NCURSES_EXPORT(void *)\n"
"#endif")
tools.replace_in_file(os.path.join("ncurses", "tinfo", "MKnames.awk"),
'\t\tprint "#define DCL(it) NCURSES_EXPORT_VAR(IT) it[]"',
'\t\tprint "#ifdef _MAKE_KEYS"\n'
'\t\tprint "#define DCL(it) static IT it[]"\n'
'\t\tprint "#else"\n'
'\t\tprint "#define DCL(it) NCURSES_EXPORT_VAR(IT) it[]"\n'
'\t\tprint "#endif"')
tools.replace_in_file(os.path.join("include", "ncurses_dll.h.in"),
"#if defined(__CYGWIN__) || defined(__MINGW32__)",
"#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(_MSC_VER)")
tools.replace_in_file(os.path.join("include", "ncurses_dll.h.in"),
"# define NCURSES_API __cdecl",
"# define NCURSES_API")
tools.replace_in_file(os.path.join("include", "ncurses_dll.h.in"),
"#undef NCURSES_DLL\n"
"#define NCURSES_STATIC",
"#undef NCURSES_DLL\n"
"#ifdef _USE_NCURSES_DLL\n"
" #ifdef _BUILD_NCURSES_DLL\n"
" #define NCURSES_DLL\n"
" #endif\n"
"#else\n"
" #define NCURSES_STATIC\n"
"#endif\n")
tools.replace_in_file(os.path.join("include", "MKterm.h.awk.in"),
"#if __MINGW32__",
"#if defined(__MINGW32__) || defined(_MSC_VER)")
tools.replace_in_file(os.path.join("include", "ncurses_mingw.h"),
"#ifdef __MINGW32__",
"#if defined(__MINGW32__) || defined(_MSC_VER)")
tools.replace_in_file(os.path.join("include", "nc_termios.h"),
"#if __MINGW32__",
"#if defined(__MINGW32__) || defined(_MSC_VER)")
tools.replace_in_file(os.path.join("include", "nc_mingw.h"),
"#ifdef __MINGW32__",
"#if defined(__MINGW32__) || defined(_MSC_VER)")
tools.replace_in_file(os.path.join("ncurses", "base", "lib_driver.c"),
"#ifdef __MINGW32__",
"#if defined(__MINGW32__) || defined(_MSC_VER)")
tools.replace_in_file(os.path.join("include", "nc_mingw.h"),
"#include <sys/time.h>",
"#if HAVE_SYS_TIME_H\n"
"#include <sys/time.h>\n"
"#endif")
tools.replace_in_file(os.path.join("progs", "progs.priv.h"),
"/* usually in <unistd.h> */",
"/* usually in <unistd.h> */\n"
"#ifndef STDIN_FILENO\n"
"#define STDIN_FILENO 0\n"
"#endif\n")
win_driver = os.path.join("ncurses", "win32con", "win_driver.c")
tools.replace_in_file(win_driver,
"#ifndef __GNUC__",
"#if 0")
# MSVC cannot check for executable permission https://msdn.microsoft.com/en-us/library/1w06ktdy.aspx
tools.replace_in_file(os.path.join("ncurses", "curses.priv.h"),
"#define X_OK\t1",
"#define X_OK\t0")
tools.replace_in_file(os.path.join("progs", "progs.priv.h"),
"#define X_OK\t1",
"#define X_OK\t0")
# TODO: below should have #ifdef _MSC_VER for compatibily...
tools.replace_in_file(win_driver,
"CHAR_INFO ci[n];",
"CHAR_INFO * ci = (CHAR_INFO*) _alloca(sizeof(CHAR_INFO) * n);")
tools.replace_in_file(win_driver,
"CHAR_INFO ci[limit];",
"CHAR_INFO * ci = (CHAR_INFO*) _alloca(sizeof(CHAR_INFO) * limit);")
tools.replace_in_file(win_driver,
"CHAR_INFO this_screen[max_cells];",
"CHAR_INFO * this_screen = (CHAR_INFO*) _alloca(sizeof(CHAR_INFO) * max_cells);")
tools.replace_in_file(win_driver,
"CHAR_INFO that_screen[max_cells];",
"CHAR_INFO * that_screen = (CHAR_INFO*) _alloca(sizeof(CHAR_INFO) * max_cells);")
tools.replace_in_file(win_driver,
"cchar_t empty[Width];",
"cchar_t * empty = (cchar_t*) _alloca(sizeof(cchar_t) * Width);")
tools.replace_in_file(win_driver,
"chtype empty[Width];",
"chtype * empty = (chtype*) _alloca(sizeof(chtype) * Width);")
tools.replace_in_file(os.path.join("ncurses", "win32con", "gettimeofday.c"),
"#include <windows.h>",
"#include <windows.h>\n"
"#include <winsock2.h>")
# we need DllMain
tools.replace_in_file(os.path.join('ncurses', 'win32con', 'win_driver.c'),
'#include <io.h>',
'#include <io.h>\n'
'#if defined(_MSC_VER) && defined(_BUILD_NCURSES_DLL)\n'
'__declspec(dllexport) BOOL WINAPI DllMain(\n'
' HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)\n'
' { return TRUE; }\n'
'#endif\n')
def _configure_autotools(self):
if not self._autotools:
args = [
'--enable-overwrite',
'--without-manpages',
'--without-tests',
'--enable-term-driver',
'--disable-echo',
'--without-profile',
'--with-sp-funcs',
'--enable-pc-files'
]
if self.options.shared:
args.extend(['--with-shared', '--without-normal', '--without-debug'])
else:
if self.settings.build_type == "Debug":
args.extend(['--without-shared', '--without-normal', '--with-debug'])
else:
args.extend(['--without-shared', '--with-normal', '--without-debug'])
if self._is_msvc:
prefix = tools.unix_path(self.package_folder)
runtime = str(self.settings.compiler.runtime)
extra_defines = '-D_USE_NCURSES_DLL' if self.options.shared else ''
args.extend(['--prefix=%s' % prefix,
'--disable-stripping', # disable, as /bin/install cannot find strip
'ac_cv_func_setvbuf_reversed=no', # asserts during configure in debug builds
'cf_cv_link_dataonly=yes', # disable broken linker workarounds
'CC=$PWD/build-aux/compile cl -nologo',
'CXX=$PWD/build-aux/compile cl -nologo',
'CFLAGS=-FS -%s' % runtime,
'CXXFLAGS=-FS -%s' % runtime,
'CPPFLAGS=-D_WIN32_WINNT=0x0600 -I%s/include %s' % (prefix, extra_defines),
'LD=link',
'LDFLAGS=user32.lib kernel32.lib -L%s/lib' % prefix,
'NM=dumpbin -symbols',
'STRIP=:',
'AR=$PWD/build-aux/ar-lib lib',
'RANLIB=:'])
if self.options.with_cpp:
args.append('--with-{}'.format("cxx-shared" if self.options.shared else "cxx"))
else:
args.extend(['--without-cxx-shared', "--without-cxx"])
self._autotools = AutoToolsBuildEnvironment(self, win_bash=tools.os_info.is_windows)
self._autotools.configure(args=args)
return self._autotools
def build(self):
tools.patch(patch_file="ncurses.patch", base_path=self._source_subfolder)
with tools.chdir(self._source_subfolder):
if self._is_msvc:
self._patch_msvc_sources()
with tools.vcvars(self.settings):
env_build = VisualStudioBuildEnvironment(self)
with tools.environment_append(env_build.vars):
autotools = self._configure_autotools()
autotools.make()
else:
autotools = self._configure_autotools()
autotools.make()
def package(self):
self.copy("COPYING", dst="licenses", src=self._source_subfolder)
with tools.chdir(self._source_subfolder):
if self._is_msvc:
with tools.vcvars(self.settings):
env_build = VisualStudioBuildEnvironment(self)
with tools.environment_append(env_build.vars):
autotools = self._configure_autotools()
autotools.install()
with tools.chdir(os.path.join(self.package_folder, "lib")):
libs = glob.glob("lib*.a")
for lib in libs:
vslib = lib[3:-2] + ".lib"
self.output.info('renaming %s into %s' % (lib, vslib))
shutil.move(lib, vslib)
else:
autotools = self._configure_autotools()
autotools.install()
def package_info(self):
libs = ['form', 'menu', 'panel', 'ncurses']
if self.options.with_cpp:
libs.append('ncurses++')
if self._is_msvc and self.options.shared:
libs = ['%s.dll.lib' % lib for lib in libs]
self.cpp_info.libs = libs
if self.options.shared:
self.cpp_info.defines.append("_USE_NCURSES_DLL=1")