Run the command without using shell=True.

It mainly allow to run command in directory containing space.
(Hello, `C:\Program Files\...`)
It would also allow to work on directory containning spaces
(`C:\Users\John Doe`) but xapian configure (at least) expressly doesn't
support it :/

- Run the command without shell=True
- The command must be a list instead of a string.
- All options must also be a list (or an iterable).
This commit is contained in:
Matthieu Gautier 2018-06-19 11:27:07 +02:00
parent e87835c61d
commit c99a9bd91f
36 changed files with 326 additions and 298 deletions

View File

@ -30,7 +30,7 @@ class PlatformNeutralEnv:
self.qmake_command = self._detect_qmake() self.qmake_command = self._detect_qmake()
if not self.qmake_command: if not self.qmake_command:
print("WARNING: qmake command not found.", file=sys.stderr) print("WARNING: qmake command not found.", file=sys.stderr)
self.mesontest_command = "{} test".format(self.meson_command) self.mesontest_command = [*self.meson_command, "test"]
def detect_platform(self): def detect_platform(self):
_platform = platform.system() _platform = platform.system()
@ -59,7 +59,7 @@ class PlatformNeutralEnv:
# Doesn't exist in PATH or isn't executable # Doesn't exist in PATH or isn't executable
continue continue
if retcode == 0: if retcode == 0:
return n return [n]
def _detect_ninja(self): def _detect_ninja(self):
@ -165,17 +165,14 @@ class BuildEnv:
@property @property
def configure_wrapper(self): def configure_wrapper(self):
wrapper = getattr(self.platformInfo, "configure_wrapper", "") try:
if wrapper: yield self.platformInfo.configure_wrapper
return "{} ".format(wrapper) except AttributeError:
else: pass
return ""
@property @property
def make_wrapper(self): def make_wrapper(self):
wrapper = getattr(self.platformInfo, "make_wrapper", "") try:
if wrapper: yield self.platformInfo.make_wrapper
return "{} ".format(wrapper) except AttributeError:
else: pass
return ""

View File

@ -16,9 +16,9 @@ class Aria2(Dependency):
def _post_prepare_script(self, context): def _post_prepare_script(self, context):
context.try_skip(self.extract_path) context.try_skip(self.extract_path)
command = "autoreconf -i" command = ["autoreconf", "-i"]
run_command(command, self.extract_path, context) run_command(command, self.extract_path, context)
class Builder(MakeBuilder): class Builder(MakeBuilder):
dependencies = ['zlib'] dependencies = ['zlib']
configure_option = "--disable-libaria2 --disable-websocket --without-sqlite3" configure_options = ["--disable-libaria2", "--disable-websocket", "--without-sqlite3"]

View File

@ -71,7 +71,7 @@ class Source:
context.try_skip(self.source_path) context.try_skip(self.source_path)
for p in self.patches: for p in self.patches:
patch_file_path = pj(SCRIPT_DIR, 'patches', p) patch_file_path = pj(SCRIPT_DIR, 'patches', p)
patch_command = "patch -p1 -i {patch}".format(patch=patch_file_path) patch_command = ["patch", "-p1", "-i", patch_file_path]
run_command(patch_command, self.source_path, context) run_command(patch_command, self.source_path, context)
def command(self, name, function, *args): def command(self, name, function, *args):
@ -170,20 +170,19 @@ class GitClone(Source):
def _git_init(self, context): def _git_init(self, context):
if option('fast_clone') and self.force_full_clone == False: if option('fast_clone') and self.force_full_clone == False:
command = "git clone --depth=1 --branch {} {} {}".format( command = ["git", "clone" , "--depth=1", "--branch", self.git_ref, self.git_remote, self.source_dir]
self.git_ref, self.git_remote, self.source_dir)
run_command(command, neutralEnv('source_dir'), context) run_command(command, neutralEnv('source_dir'), context)
else: else:
command = "git clone {} {}".format(self.git_remote, self.source_dir) command = ["git", "clone", self.git_remote, self.source_dir]
run_command(command, neutralEnv('source_dir'), context) run_command(command, neutralEnv('source_dir'), context)
command = "git checkout {}".format(self.git_ref) command = ["git", "checkout", self.git_ref]
run_command(command, self.git_path, context) run_command(command, self.git_path, context)
def _git_update(self, context): def _git_update(self, context):
command = "git fetch origin {}".format(self.git_ref) command = ["git", "fetch", "origin", self.git_ref]
run_command(command, self.git_path, context) run_command(command, self.git_path, context)
try: try:
command = "git merge --ff-only origin/{}".format(self.git_ref) command = ["git", "merge", "--ff-only", f"origin/{self.git_ref}"]
run_command(command, self.git_path, context) run_command(command, self.git_path, context)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
raise WarningMessage("Cannot update, please check log for information") raise WarningMessage("Cannot update, please check log for information")
@ -209,7 +208,10 @@ class SvnClone(Source):
def _svn_export(self, context): def _svn_export(self, context):
if os.path.exists(self.svn_path): if os.path.exists(self.svn_path):
raise SkipCommand() raise SkipCommand()
command = "svn export {} {}".format(self.svn_remote, self.svn_dir) command = [
"svn", "export",
self.svn_remote, self.svn_dir
]
run_command(command, neutralEnv('source_dir'), context) run_command(command, neutralEnv('source_dir'), context)
def prepare(self): def prepare(self):
@ -354,36 +356,37 @@ class TcCopyBuilder(Builder):
class MakeBuilder(Builder): class MakeBuilder(Builder):
configure_option_template = "{dep_options} {static_option} {env_option} --prefix {install_dir} --libdir {libdir}" configure_options = []
configure_option = "" dynamic_configure_options = ["--enable-shared", "--disable-static"]
dynamic_configure_option = "--enable-shared --disable-static" static_configure_options = ["--enable-static", "--disable-shared"]
static_configure_option = "--enable-static --disable-shared" make_options = []
make_option = "" install_options = []
install_option = ""
configure_script = "configure" configure_script = "configure"
configure_env = { configure_env = {
'_format_CFLAGS' : '{env[CFLAGS]} -O3', '_format_CFLAGS' : '{env[CFLAGS]} -O3',
'_format_CXXFLAGS': '{env[CXXFLAGS]} -O3' '_format_CXXFLAGS': '{env[CXXFLAGS]} -O3'
} }
make_target = "" make_targets = []
flatpak_buildsystem = None flatpak_buildsystem = None
@property @property
def make_install_target(self): def make_install_targets(self):
if self.buildEnv.platformInfo.build in ('iOS', "wasm"): if self.buildEnv.platformInfo.build in ('iOS', "wasm"):
return 'install' yield 'install'
return 'install-strip' else:
yield 'install-strip'
@property @property
def all_configure_option(self): def all_configure_options(self):
option = self.configure_option_template.format( yield from self.configure_options
dep_options=self.configure_option, if self.buildEnv.platformInfo.static:
static_option=self.static_configure_option if self.buildEnv.platformInfo.static else self.dynamic_configure_option, yield from self.static_configure_options
env_option=self.buildEnv.platformInfo.configure_option if not self.target.force_native_build else "", else:
install_dir=self.buildEnv.install_dir, yield from self.dynamic_configure_options
libdir=pj(self.buildEnv.install_dir, self.buildEnv.libprefix) if not self.target.force_native_build:
) yield from self.buildEnv.platformInfo.configure_options
return option yield from ('--prefix', self.buildEnv.install_dir)
yield from ('--libdir', pj(self.buildEnv.install_dir, self.buildEnv.libprefix))
def set_configure_env(self, env): def set_configure_env(self, env):
dep_conf_env = self.configure_env dep_conf_env = self.configure_env
@ -399,41 +402,43 @@ class MakeBuilder(Builder):
def _configure(self, context): def _configure(self, context):
context.try_skip(self.build_path) context.try_skip(self.build_path)
command = "{configure_wrapper}{configure_script} {configure_option}" command = [
command = command.format( *self.buildEnv.configure_wrapper,
configure_wrapper=self.buildEnv.configure_wrapper, pj(self.source_path, self.configure_script),
configure_script=pj(self.source_path, self.configure_script), *self.all_configure_options
configure_option=self.all_configure_option ]
)
env = self.get_env(cross_comp_flags=True, cross_compilers=True, cross_path=True) env = self.get_env(cross_comp_flags=True, cross_compilers=True, cross_path=True)
self.set_configure_env(env) self.set_configure_env(env)
run_command(command, self.build_path, context, env=env) run_command(command, self.build_path, context, env=env)
def _compile(self, context): def _compile(self, context):
context.try_skip(self.build_path) context.try_skip(self.build_path)
command = "{make_wrapper}make -j4 {make_target} {make_option}".format( command = [
make_wrapper=self.buildEnv.make_wrapper, *self.buildEnv.make_wrapper,
make_target=self.make_target, "make", "-j4",
make_option=self.make_option *self.make_targets,
) *self.make_options
]
env = self.get_env(cross_comp_flags=True, cross_compilers=True, cross_path=True) env = self.get_env(cross_comp_flags=True, cross_compilers=True, cross_path=True)
run_command(command, self.build_path, context, env=env) run_command(command, self.build_path, context, env=env)
def _install(self, context): def _install(self, context):
context.try_skip(self.build_path) context.try_skip(self.build_path)
command = "{make_wrapper}make {make_install_target} {make_option}".format( command = [
make_wrapper=self.buildEnv.make_wrapper, *self.buildEnv.make_wrapper,
make_install_target=self.make_install_target, "make",
make_option=self.make_option *self.make_install_targets,
) *self.make_options
]
env = self.get_env(cross_comp_flags=True, cross_compilers=True, cross_path=True) env = self.get_env(cross_comp_flags=True, cross_compilers=True, cross_path=True)
run_command(command, self.build_path, context, env=env) run_command(command, self.build_path, context, env=env)
def _make_dist(self, context): def _make_dist(self, context):
context.try_skip(self.build_path) context.try_skip(self.build_path)
command = "{make_wrapper}make dist".format( command = [
make_wrapper=self.buildEnv.make_wrapper *self.buildEnv.make_wrapper,
) "make", "dist"
]
env = self.get_env(cross_comp_flags=True, cross_compilers=True, cross_path=True) env = self.get_env(cross_comp_flags=True, cross_compilers=True, cross_path=True)
run_command(command, self.build_path, context, env=env) run_command(command, self.build_path, context, env=env)
@ -443,22 +448,18 @@ class CMakeBuilder(MakeBuilder):
def _configure(self, context): def _configure(self, context):
context.try_skip(self.build_path) context.try_skip(self.build_path)
cross_option = "" cross_options = []
if not self.target.force_native_build and self.buildEnv.cmake_crossfile: if not self.target.force_native_build and self.buildEnv.cmake_crossfile:
cross_option = "-DCMAKE_TOOLCHAIN_FILE={}".format(self.buildEnv.cmake_crossfile) cross_options += [f"-DCMAKE_TOOLCHAIN_FILE={self.buildEnv.cmake_crossfile}"]
command = ("cmake {configure_option}" command = [
" -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON" "cmake",
" -DCMAKE_INSTALL_PREFIX={install_dir}" *self.configure_options,
" -DCMAKE_INSTALL_LIBDIR={libdir}" "-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON",
" {source_path}" f"-DCMAKE_INSTALL_PREFIX={self.buildEnv.install_dir}",
" {cross_option}") f"-DCMAKE_INSTALL_LIBDIR={self.buildEnv.libprefix}",
command = command.format( self.source_path,
configure_option=self.configure_option, *cross_options
install_dir=self.buildEnv.install_dir, ]
libdir=self.buildEnv.libprefix,
source_path=self.source_path,
cross_option=cross_option
)
env = self.get_env(cross_comp_flags=True, cross_compilers=False, cross_path=True) env = self.get_env(cross_comp_flags=True, cross_compilers=False, cross_path=True)
self.set_configure_env(env) self.set_configure_env(env)
run_command(command, self.build_path, context, env=env) run_command(command, self.build_path, context, env=env)
@ -469,49 +470,42 @@ class CMakeBuilder(MakeBuilder):
class QMakeBuilder(MakeBuilder): class QMakeBuilder(MakeBuilder):
qmake_target = "" qmake_targets = []
flatpak_buildsystem = 'qmake' flatpak_buildsystem = 'qmake'
@property @property
def env_option(self): def env_options(self):
options = ""
if 'QMAKE_CC' in os.environ: if 'QMAKE_CC' in os.environ:
options += 'QMAKE_CC={} '.format(os.environ['QMAKE_CC']) yield f"QMAKE_CC={os.environ['QMAKE_CC']}"
if 'QMAKE_CXX' in os.environ: if 'QMAKE_CXX' in os.environ:
options += 'QMAKE_CXX={} '.format(os.environ['QMAKE_CXX']) yield f"QMAKE_CXX={os.environ['QMAKE_CXX']}"
return options
def _configure(self, context): def _configure(self, context):
context.try_skip(self.build_path) context.try_skip(self.build_path)
cross_option = "" command = [
command = ("{command} {configure_option}" *neutralEnv('qmake_command'),
" {env_option}" *self.configure_options,
" {source_path}" *self.env_options,
" {cross_option}") self.source_path,
command = command.format( ]
command = neutralEnv('qmake_command'),
configure_option=self.configure_option,
env_option=self.env_option,
source_path=self.source_path,
cross_option=cross_option
)
env = self.get_env(cross_comp_flags=True, cross_compilers=False, cross_path=True) env = self.get_env(cross_comp_flags=True, cross_compilers=False, cross_path=True)
self.set_configure_env(env) self.set_configure_env(env)
run_command(command, self.build_path, context, env=env) run_command(command, self.build_path, context, env=env)
def _make_dist(self, context): def _make_dist(self, context):
command = "git archive -o {build_dir}/{name}.tar.gz --prefix={name}/ HEAD" command = [
command = command.format( "git", "archive",
build_dir = self.build_path, "-o", f"{self.build_path}/{self.target_full_name()}.tar.gz",
name = self.target.full_name() f"--prefix={self.target_full_name()}/",
) "HEAD"
]
run_command(command, self.source_path, context) run_command(command, self.source_path, context)
class MesonBuilder(Builder): class MesonBuilder(Builder):
configure_option = "" configure_options = []
test_option = "" test_options = []
flatpak_buildsystem = 'meson' flatpak_buildsystem = 'meson'
@property @property
@ -519,8 +513,9 @@ class MesonBuilder(Builder):
return 'release' if option('make_release') else 'debug' return 'release' if option('make_release') else 'debug'
@property @property
def strip_option(self): def strip_options(self):
return '--strip' if option('make_release') else '' if option('make_release'):
yield '--strip'
@property @property
def library_type(self): def library_type(self):
@ -531,34 +526,26 @@ class MesonBuilder(Builder):
if os.path.exists(self.build_path): if os.path.exists(self.build_path):
shutil.rmtree(self.build_path) shutil.rmtree(self.build_path)
os.makedirs(self.build_path) os.makedirs(self.build_path)
configure_option = self.configure_option.format(buildEnv=self.buildEnv) cross_options = []
cross_option = ""
if not self.target.force_native_build and self.buildEnv.meson_crossfile: if not self.target.force_native_build and self.buildEnv.meson_crossfile:
cross_option = "--cross-file {}".format( cross_options += ["--cross-file", self.buildEnv.meson_crossfile]
self.buildEnv.meson_crossfile) command = [
command = ("{command} . {build_path}" *neutralEnv('meson_command'),
" --buildtype={build_type} {strip_option}" '.', self.build_path,
" --default-library={library_type}" f'--buildtype={self.build_type}',
" {configure_option}" *self.strip_options,
" --prefix={buildEnv.install_dir}" f'--default-library={self.library_type}',
" --libdir={buildEnv.libprefix}" *self.configure_options,
" {cross_option}") f'--prefix={self.buildEnv.install_dir}',
command = command.format( f'--libdir={self.buildEnv.libprefix}',
command=neutralEnv('meson_command'), *cross_options
build_type=self.build_type, ]
strip_option=self.strip_option,
library_type=self.library_type,
configure_option=configure_option,
build_path=self.build_path,
buildEnv=self.buildEnv,
cross_option=cross_option
)
env = self.get_env(cross_comp_flags=False, cross_compilers=False, cross_path=True) env = self.get_env(cross_comp_flags=False, cross_compilers=False, cross_path=True)
run_command(command, self.source_path, context, env=env) run_command(command, self.source_path, context, env=env)
def _compile(self, context): def _compile(self, context):
context.try_skip(self.build_path) context.try_skip(self.build_path)
command = "{} -v".format(neutralEnv('ninja_command')) command = [*neutralEnv('ninja_command'), "-v"]
env = self.get_env(cross_comp_flags=False, cross_compilers=False, cross_path=True) env = self.get_env(cross_comp_flags=False, cross_compilers=False, cross_path=True)
run_command(command, self.build_path, context, env=env) run_command(command, self.build_path, context, env=env)
@ -569,17 +556,21 @@ class MesonBuilder(Builder):
and not self.buildEnv.platformInfo.static) and not self.buildEnv.platformInfo.static)
): ):
raise SkipCommand() raise SkipCommand()
command = "{} --verbose {}".format(neutralEnv('mesontest_command'), self.test_option) command = [
*neutralEnv('mesontest_command'),
'--verbose',
*self.test_options
]
env = self.get_env(cross_comp_flags=False, cross_compilers=False, cross_path=True) env = self.get_env(cross_comp_flags=False, cross_compilers=False, cross_path=True)
run_command(command, self.build_path, context, env=env) run_command(command, self.build_path, context, env=env)
def _install(self, context): def _install(self, context):
context.try_skip(self.build_path) context.try_skip(self.build_path)
command = "{} -v install".format(neutralEnv('ninja_command')) command = [*neutralEnv('ninja_command'), '-v', 'install']
env = self.get_env(cross_comp_flags=False, cross_compilers=False, cross_path=True) env = self.get_env(cross_comp_flags=False, cross_compilers=False, cross_path=True)
run_command(command, self.build_path, context, env=env) run_command(command, self.build_path, context, env=env)
def _make_dist(self, context): def _make_dist(self, context):
command = "{} -v dist".format(neutralEnv('ninja_command')) command = [*neutralEnv('ninja_command'), "-v", "dist"]
env = self.get_env(cross_comp_flags=False, cross_compilers=False, cross_path=True) env = self.get_env(cross_comp_flags=False, cross_compilers=False, cross_path=True)
run_command(command, self.build_path, context, env=env) run_command(command, self.build_path, context, env=env)

View File

@ -17,5 +17,5 @@ class docoptcpp(Dependency):
git_ref = "3dd23e3280f213bacefdf5fcb04857bf52e90917" git_ref = "3dd23e3280f213bacefdf5fcb04857bf52e90917"
class Builder(CMakeBuilder): class Builder(CMakeBuilder):
make_install_target = 'install' make_install_targets = ['install']

View File

@ -17,7 +17,7 @@ class Gumbo(Dependency):
def _post_prepare_script(self, context): def _post_prepare_script(self, context):
context.try_skip(self.extract_path) context.try_skip(self.extract_path)
command = "./autogen.sh" command = ["./autogen.sh"]
run_command(command, self.extract_path, context) run_command(command, self.extract_path, context)
Builder = MakeBuilder Builder = MakeBuilder

View File

@ -53,7 +53,7 @@ class Icu(Dependency):
class Builder(MakeBuilder): class Builder(MakeBuilder):
subsource_dir = "source" subsource_dir = "source"
make_install_target = "install" make_install_targets = ["install"]
@classmethod @classmethod
def get_dependencies(cls, platformInfo, allDeps): def get_dependencies(cls, platformInfo, allDeps):
@ -61,20 +61,23 @@ class Icu(Dependency):
return [(plt, 'icu4c')] return [(plt, 'icu4c')]
@property @property
def configure_option(self): def configure_options(self):
options = ("--disable-samples --disable-tests --disable-extras " yield "--disable-samples"
"--disable-dyload --enable-rpath " yield "--disable-tests"
"--disable-icuio --disable-layoutex") yield "--disable-extras"
yield "--disable-dyload"
yield "--enable-rpath"
yield "--disable-icuio"
yield "--disable-layoutex"
platformInfo = self.buildEnv.platformInfo platformInfo = self.buildEnv.platformInfo
if platformInfo.build != 'native': if platformInfo.build != 'native':
icu_native_builder = get_target_step( icu_native_builder = get_target_step(
'icu4c', 'icu4c',
'native_static' if platformInfo.static else 'native_dyn') 'native_static' if platformInfo.static else 'native_dyn')
options += " --with-cross-build={} --disable-tools".format( yield f"--with-cross-build={icu_native_builder.build_path}"
icu_native_builder.build_path) yield "--disable-tools"
if platformInfo.build in ('android', 'wasm'): if platformInfo.build in ('android', 'wasm'):
options += " --with-data-packaging=archive" yield "--with-data-packaging=archive"
return options
def set_env(self, env): def set_env(self, env):
env['ICU_DATA_FILTER_FILE'] = pj(os.path.dirname(os.path.realpath(__file__)), "icu4c_data_filter.json") env['ICU_DATA_FILTER_FILE'] = pj(os.path.dirname(os.path.realpath(__file__)), "icu4c_data_filter.json")

View File

@ -40,11 +40,12 @@ class IOSFatLib(Dependency):
if f.endswith('.a') or f.endswith('.dylib'): if f.endswith('.a') or f.endswith('.dylib'):
libs.append(f) libs.append(f)
os.makedirs(pj(self.buildEnv.install_dir, 'lib'), exist_ok=True) os.makedirs(pj(self.buildEnv.install_dir, 'lib'), exist_ok=True)
command_tmp = "lipo -create {input} -output {output}"
for l in libs: for l in libs:
command = command_tmp.format( command = [
input=" ".join(pj(d, l) for d in lib_dirs), 'lipo',
output=pj(self.buildEnv.install_dir, 'lib', l)) '-create', *[pj(d, l) for d in lib_dirs],
'-output', pj(self.buildEnv.install_dir, 'lib', l)
]
run_command(command, self.buildEnv.install_dir, context) run_command(command, self.buildEnv.install_dir, context)
def build(self): def build(self):

View File

@ -13,7 +13,7 @@ class KiwixDesktop(Dependency):
class Builder(QMakeBuilder): class Builder(QMakeBuilder):
dependencies = ["qt", "qtwebengine", "libkiwix", "aria2"] dependencies = ["qt", "qtwebengine", "libkiwix", "aria2"]
make_install_target = 'install' make_install_targets = ['install']
configure_env = None configure_env = None
flatpack_build_options = { flatpack_build_options = {
@ -23,15 +23,12 @@ class KiwixDesktop(Dependency):
} }
@property @property
def configure_option(self): def configure_options(self):
if self.buildEnv.platformInfo.name == 'flatpak': if self.buildEnv.platformInfo.name == 'flatpak':
options = [ yield 'QMAKE_INCDIR+=/app/include/QtWebEngine'
'QMAKE_INCDIR+=/app/include/QtWebEngine', yield 'QMAKE_INCDIR+=/app/include/QtWebEngineCore'
'QMAKE_INCDIR+=/app/include/QtWebEngineCore', yield 'QMAKE_INCDIR+=/app/include/QtWebEngineWidgets'
'QMAKE_INCDIR+=/app/include/QtWebEngineWidgets'
]
else: else:
options = ["PREFIX={}".format(self.buildEnv.install_dir)] yield f"PREFIX={self.buildEnv.install_dir}"
if self.buildEnv.platformInfo.static: if self.buildEnv.platformInfo.static:
options.append('"CONFIG+=static"') yield 'CONFIG+=static'
return " ".join(options)

View File

@ -15,7 +15,6 @@ class KiwixTools(Dependency):
dependencies = ["libkiwix"] dependencies = ["libkiwix"]
@property @property
def configure_option(self): def configure_options(self):
if self.buildEnv.platformInfo.static: if self.buildEnv.platformInfo.static:
return "-Dstatic-linkage=true" yield "-Dstatic-linkage=true"
return ""

View File

@ -20,11 +20,11 @@ class LibCurl(Dependency):
class Builder(MakeBuilder): class Builder(MakeBuilder):
dependencies = ['zlib'] dependencies = ['zlib']
configure_option = " ".join( configure_options = [
["--without-{}".format(p) *[f"--without-{p}" for p in
for p in ('libssh2', 'ssl', 'libmetalink', 'librtmp', ('libssh2', 'ssl', 'libmetalink', 'librtmp', 'nghttp2', 'libidn2', 'brotli')
'nghttp2', 'libidn2', 'brotli')] + ],
["--disable-{}".format(p) *[f"--disable-{p}" for p in
for p in ('ftp', 'file', 'ldap', 'ldaps', 'rtsp', 'dict', ('ftp', 'file', 'ldap', 'ldaps', 'rtsp', 'dict', 'telnet',
'telnet', 'tftp', 'pop3', 'imap', 'smb', 'smtp', 'tftp', 'pop3', 'imap', 'smb', 'smtp', 'gopher', 'manual')]
'gopher', 'manual')]) ]

View File

@ -17,7 +17,7 @@ class Libkiwix(Dependency):
class Builder(MesonBuilder): class Builder(MesonBuilder):
dependencies = ["pugixml", "libzim", "zlib", "lzma", "libcurl", "libmicrohttpd", "icu4c", "mustache", "xapian-core"] dependencies = ["pugixml", "libzim", "zlib", "lzma", "libcurl", "libmicrohttpd", "icu4c", "mustache", "xapian-core"]
strip_option = '' strip_options = []
@property @property
def build_type(self): def build_type(self):
@ -26,15 +26,17 @@ class Libkiwix(Dependency):
return super().build_type return super().build_type
@property @property
def configure_option(self): def configure_options(self):
platformInfo = self.buildEnv.platformInfo platformInfo = self.buildEnv.platformInfo
if platformInfo.build == 'android': if platformInfo.build == 'android':
return '-Dstatic-linkage=true -Dwerror=false' yield '-Dstatic-linkage=true'
yield '-Dwerror=false'
if platformInfo.build == 'iOS':
yield '-Db_bitcode=true'
if platformInfo.name == 'flatpak': if platformInfo.name == 'flatpak':
return '--wrap-mode=nodownload' yield '--wrap-mode=nodownload'
if platformInfo.mixed and option('target') == 'libkiwix': if platformInfo.mixed and option('target') == 'libkiwix':
return "-Dstatic-linkage=true" yield "-Dstatic-linkage=true"
return ''
@property @property
def library_type(self): def library_type(self):

View File

@ -21,12 +21,11 @@ class LibMagic(Dependency):
class Builder(MakeBuilder): class Builder(MakeBuilder):
@property @property
def configure_option(self): def configure_options(self):
return ("--disable-bzlib " yield "--disable-bzlib"
"--disable-xzlib " yield "--disable-xzlib"
"--disable-zstdlib " yield "--disable-zstdlib"
"--disable-lzlib " yield "--disable-lzlib"
)
@classmethod @classmethod
def get_dependencies(cls, platformInfo, allDeps): def get_dependencies(cls, platformInfo, allDeps):
@ -39,10 +38,12 @@ class LibMagic(Dependency):
if platformInfo.build == 'native': if platformInfo.build == 'native':
return super()._compile(context) return super()._compile(context)
context.try_skip(self.build_path) context.try_skip(self.build_path)
command = "make -j4 {make_target} {make_option}".format( command = [
make_target=self.make_target, "make",
make_option=self.make_option "-j4",
) *self.make_targets,
*self.make_options
]
env = self.buildEnv.get_env(cross_comp_flags=True, cross_compilers=True, cross_path=True) env = self.buildEnv.get_env(cross_comp_flags=True, cross_compilers=True, cross_path=True)
libmagic_native_builder = get_target_step('libmagic', 'native_static') libmagic_native_builder = get_target_step('libmagic', 'native_static')
env['PATH'] = ':'.join([pj(libmagic_native_builder.build_path, 'src'), env['PATH']]) env['PATH'] = ':'.join([pj(libmagic_native_builder.build_path, 'src'), env['PATH']])

View File

@ -14,4 +14,4 @@ class MicroHttpd(Dependency):
'https://ftp.gnu.org/gnu/libmicrohttpd/libmicrohttpd-0.9.76.tar.gz') 'https://ftp.gnu.org/gnu/libmicrohttpd/libmicrohttpd-0.9.76.tar.gz')
class Builder(MakeBuilder): class Builder(MakeBuilder):
configure_option = "--disable-https --without-libgcrypt --without-libcurl --disable-doc --disable-examples" configure_options = ["--disable-https", "--without-libgcrypt", "--without-libcurl", "--disable-doc", "--disable-examples"]

View File

@ -13,8 +13,8 @@ class Libzim(Dependency):
git_dir = "libzim" git_dir = "libzim"
class Builder(MesonBuilder): class Builder(MesonBuilder):
test_option = "-t 8" test_options = ["-t", "8"]
strip_option = '' strip_options = []
@property @property
def build_type(self): def build_type(self):
@ -30,24 +30,22 @@ class Libzim(Dependency):
return deps return deps
@property @property
def configure_option(self): def configure_options(self):
platformInfo = self.buildEnv.platformInfo platformInfo = self.buildEnv.platformInfo
config_options = []
if platformInfo.build == 'android': if platformInfo.build == 'android':
config_options.append("-DUSE_BUFFER_HEADER=false") yield "-DUSE_BUFFER_HEADER=false"
config_options.append("-Dstatic-linkage=true") yield "-Dstatic-linkage=true"
if platformInfo.mixed and option('target') == 'libzim': if platformInfo.mixed and option('target') == 'libzim':
config_options.append("-Dstatic-linkage=true") yield "-Dstatic-linkage=true"
if platformInfo.name == "flatpak": if platformInfo.name == "flatpak":
config_options.append("--wrap-mode=nodownload") yield "--wrap-mode=nodownload"
config_options.append("-Dtest_data_dir=none") yield "-Dtest_data_dir=none"
if platformInfo.name == "wasm": if platformInfo.name == "wasm":
config_options.append("-Dexamples=false") yield "-Dexamples=false"
config_options.append("-DUSE_MMAP=false") yield "-DUSE_MMAP=false"
if platformInfo.name not in ("flatpak", "wasm"): if platformInfo.name not in ("flatpak", "wasm"):
zim_testing_suite = get_target_step('zim-testing-suite', 'source') zim_testing_suite = get_target_step('zim-testing-suite', 'source')
config_options.append('-Dtest_data_dir={}'.format(zim_testing_suite.source_path)) yield '-Dtest_data_dir={}'.format(zim_testing_suite.source_path)
return " ".join(config_options)
@property @property
def library_type(self): def library_type(self):

View File

@ -16,13 +16,13 @@ class lzma(Dependency):
class Builder(MakeBuilder): class Builder(MakeBuilder):
@property @property
def configure_option(self): def configure_options(self):
return ("--disable-xz " return ["--disable-xz",
"--disable-xzdec " "--disable-xzdec",
"--disable-lzmadec " "--disable-lzmadec",
"--disable-lzmainfo " "--disable-lzmainfo",
"--disable-lzma-links " "--disable-lzma-links",
"--disable-scripts " "--disable-scripts",
"--disable-doc " "--disable-doc",
# "--disable-symbol-versions " # "--disable-symbol-versions"
) ]

View File

@ -16,4 +16,4 @@ class Pugixml(Dependency):
class Builder(MesonBuilder): class Builder(MesonBuilder):
build_type = 'release' build_type = 'release'
strip_option = '' strip_options = []

View File

@ -21,12 +21,23 @@ class Qt(Dependency):
class Builder(MakeBuilder): class Builder(MakeBuilder):
dependencies = ['icu4c', 'zlib'] dependencies = ['icu4c', 'zlib']
configure_option_template = "{dep_options} {static_option} {env_option} -prefix {install_dir} -libdir {libdir}" dynamic_configure_options = ["-shared"]
dynamic_configure_option = "-shared" static_configure_options = ["-static"]
static_configure_option = "-static"
@property @property
def configure_option(self): def all_configure_options(self):
yield from self.configure_options
if self.buildEnv.platformInfo.static:
yield from self.static_configure_options
else:
yield from self.dynamic_configure_options
if not self.target.force_native_build:
yield from self.buildEnv.platformInfo.configure_options
yield from ('-prefix', self.buildEnv.install_dir)
yield from ('-libdir', pj(self.buildEnv.install_dir, self.buildEnv.libprefix))
@property
def configure_options(self):
skip_modules = [ skip_modules = [
'qt3d', 'qt3d',
'qtcanvas3d', 'qtcanvas3d',
@ -55,10 +66,15 @@ class Qt(Dependency):
'qtwebglplugin', 'qtwebglplugin',
'qtwebsockets', 'qtwebsockets',
# 'qtwebview', # 'qtwebview',
] ]
skip_modules = " ".join("-skip {}".format(m) for m in skip_modules) yield '-recheck'
options = "-recheck -opensource -confirm-license -ccache -make libs {}".format(skip_modules) yield '-opensource'
return options yield '-confirm-license'
yield '-ccache'
yield from ('-make', 'libs')
for module in skip_modules:
yield from ('-skip', module)
class QtWebEngine(Dependency): class QtWebEngine(Dependency):
name = "qtwebengine" name = "qtwebengine"

View File

@ -47,13 +47,13 @@ class android_ndk(Dependency):
context.try_skip(self.build_path) context.try_skip(self.build_path)
script = pj(self.source_path, 'build/tools/make_standalone_toolchain.py') script = pj(self.source_path, 'build/tools/make_standalone_toolchain.py')
add_execution_right(script) add_execution_right(script)
command = '{script} --arch={arch} --api={api} --install-dir={install_dir} --force' command = [
command = command.format( script,
script=script, f'--arch={self.arch}',
arch=self.arch, f'--api={self.api}',
api=self.api, f'--install-dir={self.install_path}',
install_dir=self.install_path '--force'
) ]
env = self.buildEnv.get_env(cross_comp_flags=False, cross_compilers=False, cross_path=False) env = self.buildEnv.get_env(cross_comp_flags=False, cross_compilers=False, cross_path=False)
run_command(command, self.build_path, context, env=env) run_command(command, self.build_path, context, env=env)

View File

@ -31,12 +31,12 @@ class emsdk(Dependency):
def _install(self, context): def _install(self, context):
context.try_skip(self.build_path) context.try_skip(self.build_path)
command = "./emsdk install 3.1.24" command = ["./emsdk", "install", "3.1.24"]
run_command(command, self.install_path, context) run_command(command, self.install_path, context)
def _activate(self, context): def _activate(self, context):
context.try_skip(self.build_path) context.try_skip(self.build_path)
command = "./emsdk activate 3.1.24" command = ["./emsdk", "activate", "3.1.24"]
run_command(command, self.install_path, context) run_command(command, self.install_path, context)

View File

@ -13,21 +13,23 @@ class org_kde(Dependency):
class Builder(Builder): class Builder(Builder):
def _setup_remote(self, context): def _setup_remote(self, context):
command = "flatpak --user remote-add --if-not-exists {remote_name} {remote_url}" command = [
command = command.format( "flatpak",
remote_name = 'flathub', "--user", "remote-add", "--if-not-exists",
remote_url = 'https://flathub.org/repo/flathub.flatpakrepo' "flathub",
) "https://flathub.org/repo/flathub.flatpakrepo"
]
env = self.buildEnv.get_env(cross_comp_flags=False, cross_compilers=False, cross_path=False) env = self.buildEnv.get_env(cross_comp_flags=False, cross_compilers=False, cross_path=False)
run_command(command, self.buildEnv.build_dir, context, env=env) run_command(command, self.buildEnv.build_dir, context, env=env)
def _install_sdk(self, context): def _install_sdk(self, context):
command = "flatpak --user install --noninteractive --verbose -y {remote_name} {name}.Sdk//{version} {name}.Platform//{version}" command = [
command = command.format( "flatpak",
remote_name = 'flathub', "--user", "install", "--noninteractive", "--verbose", "-y",
name = self.target.name, "flathub",
version = self.target.version() f"{self.target.name}.Sdk//{self.target.version()}",
) f"{self.target.name}.Platform//{self.target.version()}"
]
env = self.buildEnv.get_env(cross_comp_flags=False, cross_compilers=False, cross_path=False) env = self.buildEnv.get_env(cross_comp_flags=False, cross_compilers=False, cross_path=False)
run_command(command, self.buildEnv.build_dir, context, env=env) run_command(command, self.buildEnv.build_dir, context, env=env)
@ -44,25 +46,25 @@ class io_qt_qtwebengine(Dependency):
class Builder(Builder): class Builder(Builder):
def _setup_remote(self, context): def _setup_remote(self, context):
command = "flatpak --user remote-add --if-not-exists {remote_name} {remote_url}" command = [
command = command.format( "flatpak",
remote_name = 'flathub', "--user", "remote-add", "--if-not-exists",
remote_url = 'https://flathub.org/repo/flathub.flatpakrepo' "flathub",
) "https://flathub.org/repo/flathub.flatpakrepo"
]
env = self.buildEnv.get_env(cross_comp_flags=False, cross_compilers=False, cross_path=False) env = self.buildEnv.get_env(cross_comp_flags=False, cross_compilers=False, cross_path=False)
run_command(command, self.buildEnv.build_dir, context, env=env) run_command(command, self.buildEnv.build_dir, context, env=env)
def _install_sdk(self, context): def _install_sdk(self, context):
command = "flatpak --user install -y {remote_name} {name}.BaseApp//{version}" command = [
command = command.format( "flatpak",
remote_name = 'flathub', "--user", "install", "-y",
name = self.target.name, "flathub",
version = self.target.version() f"{self.target.name}.BaseApp//{self.target.version()}"
) ]
env = self.buildEnv.get_env(cross_comp_flags=False, cross_compilers=False, cross_path=False) env = self.buildEnv.get_env(cross_comp_flags=False, cross_compilers=False, cross_path=False)
run_command(command, self.buildEnv.build_dir, context, env=env) run_command(command, self.buildEnv.build_dir, context, env=env)
def build(self): def build(self):
self.command('setup_remote', self._setup_remote) self.command('setup_remote', self._setup_remote)
self.command('install_sdk', self._install_sdk) self.command('install_sdk', self._install_sdk)

View File

@ -17,9 +17,14 @@ class UUID(Dependency):
extract_dir = 'e2fsprogs-libs-1.43.4' extract_dir = 'e2fsprogs-libs-1.43.4'
class Builder(MakeBuilder): class Builder(MakeBuilder):
configure_option = ("--enable-libuuid --disable-debugfs --disable-imager --disable-resizer --disable-defrag --enable-fsck" configure_options = ["--enable-libuuid",
" --disable-uuidd") "--disable-debugfs",
"--disable-imager",
"--disable-resizer",
"--disable-defrag",
"--enable-fsck",
"--disable-uuidd"]
configure_env = {'_format_CFLAGS': "{env.CFLAGS} -O3 -fPIC"} configure_env = {'_format_CFLAGS': "{env.CFLAGS} -O3 -fPIC"}
static_configure_option = dynamic_configure_option = "" static_configure_options = dynamic_configure_options = []
make_target = 'libs' make_targets = ['libs']
make_install_target = 'install-libs' make_install_targets = ['install-libs']

View File

@ -16,7 +16,11 @@ class Xapian(Dependency):
'30d3518172084f310dab86d262b512718a7f9a13635aaa1a188e61dc26b2288c') '30d3518172084f310dab86d262b512718a7f9a13635aaa1a188e61dc26b2288c')
class Builder(MakeBuilder): class Builder(MakeBuilder):
configure_option = "--disable-sse --disable-backend-chert --disable-backend-remote --disable-documentation" configure_options = [
"--disable-sse",
"--disable-backend-chert",
"--disable-backend-remote",
"--disable-documentation"]
configure_env = {'_format_LDFLAGS': "{env.LDFLAGS} -L{buildEnv.install_dir}/{buildEnv.libprefix}", configure_env = {'_format_LDFLAGS': "{env.LDFLAGS} -L{buildEnv.install_dir}/{buildEnv.libprefix}",
'_format_CXXFLAGS': "{env.CXXFLAGS} -O3 -I{buildEnv.install_dir}/include"} '_format_CXXFLAGS': "{env.CXXFLAGS} -O3 -I{buildEnv.install_dir}/include"}

View File

@ -20,11 +20,9 @@ class ZimTools(Dependency):
return base_deps return base_deps
@property @property
def configure_option(self): def configure_options(self):
base_option = ""
# We don't build zimwriterfs on win32, and so we don't have magic # We don't build zimwriterfs on win32, and so we don't have magic
if self.buildEnv.platformInfo.build != 'win32': if self.buildEnv.platformInfo.build != 'win32':
base_option += " -Dmagic-install-prefix={buildEnv.install_dir}" yield f"-Dmagic-install-prefix={self.buildEnv.install_dir}"
if self.buildEnv.platformInfo.static: if self.buildEnv.platformInfo.static:
base_option += " -Dstatic-linkage=true" yield "-Dstatic-linkage=true"
return base_option

View File

@ -18,10 +18,9 @@ class zlib(Dependency):
patches = ['zlib_std_libname.patch'] patches = ['zlib_std_libname.patch']
class Builder(MakeBuilder): class Builder(MakeBuilder):
dynamic_configure_option = "--shared" dynamic_configure_options = ["--shared"]
static_configure_option = "--static" static_configure_options = ["--static"]
make_install_target = 'install' make_install_targets = ['install']
configure_option_template = "{dep_options} {static_option} --prefix {install_dir} --libdir {libdir}"
def _pre_build_script(self, context): def _pre_build_script(self, context):
context.try_skip(self.build_path) context.try_skip(self.build_path)
@ -34,20 +33,27 @@ class zlib(Dependency):
return super()._configure(context) return super()._configure(context)
@property @property
def make_option(self): def all_configure_options(self):
if self.buildEnv.platformInfo.build == 'win32': yield from self.configure_options
return "--makefile win32/Makefile.gcc PREFIX={host}- SHARED_MODE={static} INCLUDE_PATH={include_path} LIBRARY_PATH={library_path} BINARY_PATH={binary_path}".format( yield from self.static_configure_options if self.buildEnv.platformInfo.static else self.dynamic_configure_options
host='i686-w64-mingw32', yield from ('--prefix', self.buildEnv.install_dir)
static="0" if self.buildEnv.platformInfo.static else "1", yield from ('--libdir', pj(self.buildEnv.install_dir, self.buildEnv.libprefix))
include_path=pj(self.buildEnv.install_dir, 'include'),
library_path=pj(self.buildEnv.install_dir, self.buildEnv.libprefix),
binary_path=pj(self.buildEnv.install_dir, 'bin'),
)
return ""
@property @property
def make_target(self): def make_options(self):
if self.buildEnv.platformInfo.build != 'win32':
return
yield "--makefile"
yield "win32/Makefile.gcc"
yield "PREFIX=i686-w64-mingw32-",
yield "SHARED_MODE={}".format("0" if self.buildEnv.platformInfo.static else "1"),
yield "INCLUDE_PATH={}".format(pj(self.buildEnv.install_dir, 'include')),
yield "LIBRARY_PATH={}".format(pj(self.buildEnv.install_dir, self.buildEnv.libprefix)),
yield "BINARY_PATH={}".format(pj(self.buildEnv.install_dir, 'bin'))
@property
def make_targets(self):
if self.buildEnv.platformInfo.static: if self.buildEnv.platformInfo.static:
return "static" return ["static"]
else: else:
return "shared" return ["shared"]

View File

@ -18,5 +18,5 @@ class zstd(Dependency):
class Builder(MesonBuilder): class Builder(MesonBuilder):
subsource_dir = 'build/meson' subsource_dir = 'build/meson'
build_type = 'release' build_type = 'release'
strip_option = '' strip_options = []
configure_option = '-Dbin_programs=false -Dbin_contrib=false' configure_options = ['-Dbin_programs=false', '-Dbin_contrib=false']

View File

@ -223,8 +223,12 @@ class FlatpakBuilder:
def build(self): def build(self):
log = pj(self.platform.buildEnv.log_dir, 'cmd_build_flatpak.log') log = pj(self.platform.buildEnv.log_dir, 'cmd_build_flatpak.log')
context = Context('build', log, False) context = Context('build', log, False)
command = "flatpak-builder --user --ccache --force-clean --keep-build-dirs --disable-rofiles-fuse --repo=repo builddir {id}.json" command = [
command = command.format(id = MANIFEST['app-id']) "flatpak-builder",
"--user", "--ccache", "--force-clean", "--keep-build-dirs",
"--disable-rofiles-fuse", "--repo=repo", "builddir",
f"{MANIFEST['app-id']}.json"
]
try: try:
run_command(command, self.platform.buildEnv.build_dir, context, env=self.platform.get_env()) run_command(command, self.platform.buildEnv.build_dir, context, env=self.platform.get_env())
context._finalise() context._finalise()
@ -236,8 +240,12 @@ class FlatpakBuilder:
def bundle(self): def bundle(self):
log = pj(self.platform.buildEnv.log_dir, 'cmd_bundle_flatpak.log') log = pj(self.platform.buildEnv.log_dir, 'cmd_bundle_flatpak.log')
context = Context('bundle', log, False) context = Context('bundle', log, False)
command = "flatpak build-bundle repo {id}.flatpak {id}" app_id = MANIFEST['app-id']
command = command.format(id = MANIFEST['app-id']) command = [
"flatpak", "build-bundle", "repo",
f"{app_id}.flatpak",
app_id
]
try: try:
run_command(command, self.platform.buildEnv.build_dir, context, env=self.platform.get_env()) run_command(command, self.platform.buildEnv.build_dir, context, env=self.platform.get_env())
context._finalise() context._finalise()

View File

@ -90,8 +90,8 @@ class AndroidPlatformInfo(PlatformInfo):
env[k] = v env[k] = v
@property @property
def configure_option(self): def configure_options(self):
return '--host={}'.format(self.arch_full) yield '--host={}'.format(self.arch_full)
def finalize_setup(self): def finalize_setup(self):
super().finalize_setup() super().finalize_setup()

View File

@ -65,8 +65,8 @@ class ArmPlatformInfo(PlatformInfo):
return "exe_wrapper = 'qemu-arm'" return "exe_wrapper = 'qemu-arm'"
@property @property
def configure_option(self): def configure_options(self):
return '--host={}'.format(self.arch_full) yield '--host={}'.format(self.arch_full)
def get_bin_dir(self): def get_bin_dir(self):
return [pj(self.root_path, 'bin')] return [pj(self.root_path, 'bin')]

View File

@ -23,7 +23,7 @@ class PlatformInfo(metaclass=_MetaPlatform):
all_platforms = {} all_platforms = {}
all_running_platforms = {} all_running_platforms = {}
toolchain_names = [] toolchain_names = []
configure_option = "" configure_options = []
mixed = False mixed = False
libdir = None libdir = None

View File

@ -31,8 +31,8 @@ class I586PlatformInfo(PlatformInfo):
} }
@property @property
def configure_option(self): def configure_options(self):
return '--host={}'.format(self.arch_full) yield f'--host={self.arch_full}'
@property @property
def binaries(self): def binaries(self):

View File

@ -118,8 +118,8 @@ class ApplePlatformInfo(PlatformInfo):
} }
@property @property
def configure_option(self): def configure_options(self):
return '--host={}'.format(self.host) yield f'--host={self.host}'
class iOSArm64(ApplePlatformInfo): class iOSArm64(ApplePlatformInfo):

View File

@ -62,8 +62,8 @@ class MuslPlatformInfo(PlatformInfo):
return f"exe_wrapper = '{self.qemu}'" return f"exe_wrapper = '{self.qemu}'"
@property @property
def configure_option(self): def configure_options(self):
return '--host={}'.format(self.arch_full) return [f'--host={self.arch_full}']
def get_bin_dir(self): def get_bin_dir(self):
return [pj(self.root_path, 'bin')] return [pj(self.root_path, 'bin')]

View File

@ -59,9 +59,9 @@ class WasmPlatformInfo(PlatformInfo):
return binaries return binaries
@property @property
def configure_option(self): def configure_options(self):
#return "" #return ""
return '--host={}'.format(self.arch_full) return [f'--host={self.arch_full}']
@property @property
def configure_wrapper(self): def configure_wrapper(self):

View File

@ -63,8 +63,8 @@ class Win32PlatformInfo(PlatformInfo):
return "exe_wrapper = 'wine'" return "exe_wrapper = 'wine'"
@property @property
def configure_option(self): def configure_options(self):
return '--host={}'.format(self.arch_full) yield f'--host={self.arch_full}'
def set_compiler(self, env): def set_compiler(self, env):
for k, v in self.binaries.items(): for k, v in self.binaries.items():

View File

@ -63,8 +63,8 @@ class Win64PlatformInfo(PlatformInfo):
return "exe_wrapper = 'wine'" return "exe_wrapper = 'wine'"
@property @property
def configure_option(self): def configure_options(self):
return '--host={}'.format(self.arch_full) return [f'--host={self.arch_full}']
def set_compiler(self, env): def set_compiler(self, env):
for k, v in self.binaries.items(): for k, v in self.binaries.items():

View File

@ -294,7 +294,7 @@ def run_command(command, cwd, context, *, env=None, input=None):
kwargs = dict() kwargs = dict()
if input: if input:
kwargs['stdin'] = subprocess.PIPE kwargs['stdin'] = subprocess.PIPE
process = subprocess.Popen(command, shell=True, cwd=cwd, env=env, stdout=log or sys.stdout, stderr=subprocess.STDOUT, **kwargs) process = subprocess.Popen(command, cwd=cwd, env=env, stdout=log or sys.stdout, stderr=subprocess.STDOUT, **kwargs)
if input: if input:
input = input.encode() input = input.encode()
while True: while True: