1# Copyright 2015 The Meson development team 2 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6 7# http://www.apache.org/licenses/LICENSE-2.0 8 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15'''This module provides helper functions for RPM related 16functionality such as generating template RPM spec file.''' 17 18from .. import build 19from .. import compilers 20import datetime 21from .. import mlog 22from . import GirTarget, TypelibTarget 23from . import ExtensionModule 24from ..interpreterbase import noKwargs 25 26import os 27 28class RPMModule(ExtensionModule): 29 def __init__(self, interpreter): 30 super().__init__(interpreter) 31 self.methods.update({ 32 'generate_spec_template': self.generate_spec_template, 33 }) 34 35 @noKwargs 36 def generate_spec_template(self, state, args, kwargs): 37 required_compilers = self.__get_required_compilers(state) 38 proj = state.project_name.replace(' ', '_').replace('\t', '_') 39 so_installed = False 40 devel_subpkg = False 41 files = set() 42 files_devel = set() 43 to_delete = set() 44 for target in state.targets.values(): 45 if isinstance(target, build.Executable) and target.need_install: 46 files.add('%%{_bindir}/%s' % target.get_filename()) 47 elif isinstance(target, build.SharedLibrary) and target.need_install: 48 files.add('%%{_libdir}/%s' % target.get_filename()) 49 for alias in target.get_aliases(): 50 if alias.endswith('.so'): 51 files_devel.add('%%{_libdir}/%s' % alias) 52 else: 53 files.add('%%{_libdir}/%s' % alias) 54 so_installed = True 55 elif isinstance(target, build.StaticLibrary) and target.need_install: 56 to_delete.add('%%{buildroot}%%{_libdir}/%s' % target.get_filename()) 57 mlog.warning('removing', mlog.bold(target.get_filename()), 58 'from package because packaging static libs not recommended') 59 elif isinstance(target, GirTarget) and target.should_install(): 60 files_devel.add('%%{_datadir}/gir-1.0/%s' % target.get_filename()[0]) 61 elif isinstance(target, TypelibTarget) and target.should_install(): 62 files.add('%%{_libdir}/girepository-1.0/%s' % target.get_filename()[0]) 63 for header in state.headers: 64 if header.get_install_subdir(): 65 files_devel.add('%%{_includedir}/%s/' % header.get_install_subdir()) 66 else: 67 for hdr_src in header.get_sources(): 68 files_devel.add('%%{_includedir}/%s' % hdr_src) 69 for man in state.man: 70 for man_file in man.get_sources(): 71 if man.locale: 72 files.add('%%{_mandir}/%s/man%u/%s.*' % (man.locale, int(man_file.split('.')[-1]), man_file)) 73 else: 74 files.add('%%{_mandir}/man%u/%s.*' % (int(man_file.split('.')[-1]), man_file)) 75 if files_devel: 76 devel_subpkg = True 77 78 filename = os.path.join(state.environment.get_build_dir(), 79 '%s.spec' % proj) 80 with open(filename, 'w+', encoding='utf-8') as fn: 81 fn.write('Name: %s\n' % proj) 82 fn.write('Version: # FIXME\n') 83 fn.write('Release: 1%{?dist}\n') 84 fn.write('Summary: # FIXME\n') 85 fn.write('License: # FIXME\n') 86 fn.write('\n') 87 fn.write('Source0: %{name}-%{version}.tar.xz # FIXME\n') 88 fn.write('\n') 89 fn.write('BuildRequires: meson\n') 90 for compiler in required_compilers: 91 fn.write('BuildRequires: %s\n' % compiler) 92 for dep in state.environment.coredata.deps.host: 93 fn.write('BuildRequires: pkgconfig(%s)\n' % dep[0]) 94# ext_libs and ext_progs have been removed from coredata so the following code 95# no longer works. It is kept as a reminder of the idea should anyone wish 96# to re-implement it. 97# 98# for lib in state.environment.coredata.ext_libs.values(): 99# name = lib.get_name() 100# fn.write('BuildRequires: {} # FIXME\n'.format(name)) 101# mlog.warning('replace', mlog.bold(name), 'with the real package.', 102# 'You can use following command to find package which ' 103# 'contains this lib:', 104# mlog.bold("dnf provides '*/lib{}.so'".format(name))) 105# for prog in state.environment.coredata.ext_progs.values(): 106# if not prog.found(): 107# fn.write('BuildRequires: %%{_bindir}/%s # FIXME\n' % 108# prog.get_name()) 109# else: 110# fn.write('BuildRequires: {}\n'.format(prog.get_path())) 111 fn.write('\n') 112 fn.write('%description\n') 113 fn.write('\n') 114 if devel_subpkg: 115 fn.write('%package devel\n') 116 fn.write('Summary: Development files for %{name}\n') 117 fn.write('Requires: %{name}%{?_isa} = %{?epoch:%{epoch}:}{version}-%{release}\n') 118 fn.write('\n') 119 fn.write('%description devel\n') 120 fn.write('Development files for %{name}.\n') 121 fn.write('\n') 122 fn.write('%prep\n') 123 fn.write('%autosetup\n') 124 fn.write('\n') 125 fn.write('%build\n') 126 fn.write('%meson\n') 127 fn.write('%meson_build\n') 128 fn.write('\n') 129 fn.write('%install\n') 130 fn.write('%meson_install\n') 131 if to_delete: 132 fn.write('rm -vf %s\n' % ' '.join(to_delete)) 133 fn.write('\n') 134 fn.write('%check\n') 135 fn.write('%meson_test\n') 136 fn.write('\n') 137 fn.write('%files\n') 138 for f in files: 139 fn.write('%s\n' % f) 140 fn.write('\n') 141 if devel_subpkg: 142 fn.write('%files devel\n') 143 for f in files_devel: 144 fn.write('%s\n' % f) 145 fn.write('\n') 146 if so_installed: 147 fn.write('%post -p /sbin/ldconfig\n') 148 fn.write('%postun -p /sbin/ldconfig\n') 149 fn.write('\n') 150 fn.write('%changelog\n') 151 fn.write('* %s meson <meson@example.com> - \n' % 152 datetime.date.today().strftime('%a %b %d %Y')) 153 fn.write('- \n') 154 fn.write('\n') 155 mlog.log('RPM spec template written to %s.spec.\n' % proj) 156 157 def __get_required_compilers(self, state): 158 required_compilers = set() 159 for compiler in state.environment.coredata.compilers.host.values(): 160 # Elbrus has one 'lcc' package for every compiler 161 if isinstance(compiler, compilers.GnuCCompiler): 162 required_compilers.add('gcc') 163 elif isinstance(compiler, compilers.GnuCPPCompiler): 164 required_compilers.add('gcc-c++') 165 elif isinstance(compiler, compilers.ElbrusCCompiler): 166 required_compilers.add('lcc') 167 elif isinstance(compiler, compilers.ElbrusCPPCompiler): 168 required_compilers.add('lcc') 169 elif isinstance(compiler, compilers.ElbrusFortranCompiler): 170 required_compilers.add('lcc') 171 elif isinstance(compiler, compilers.ValaCompiler): 172 required_compilers.add('vala') 173 elif isinstance(compiler, compilers.GnuFortranCompiler): 174 required_compilers.add('gcc-gfortran') 175 elif isinstance(compiler, compilers.GnuObjCCompiler): 176 required_compilers.add('gcc-objc') 177 elif compiler == compilers.GnuObjCPPCompiler: 178 required_compilers.add('gcc-objc++') 179 else: 180 mlog.log('RPM spec file not created, generation not allowed for:', 181 mlog.bold(compiler.get_id())) 182 return required_compilers 183 184 185def initialize(*args, **kwargs): 186 return RPMModule(*args, **kwargs) 187