Skip to main content
  • Home
  • Development
  • Documentation
  • Donate
  • Operational login
  • Browse the archive

swh logo
SoftwareHeritage
Software
Heritage
Archive
Features
  • Search

  • Downloads

  • Save code now

  • Add forge now

  • Help

Raw File Download

To reference or cite the objects present in the Software Heritage archive, permalinks based on SoftWare Hash IDentifiers (SWHIDs) must be used.
Select below a type of object currently browsed in order to display its associated SWHID and permalink.

  • content
content badge
swh:1:cnt:2c41a08ab360e29718f7e9af4e6ba5636c73bd91

This interface enables to generate software citations, provided that the root directory of browsed objects contains a citation.cff or codemeta.json file.
Select below a type of object currently browsed in order to generate citations for them.

  • content
Generate software citation in BibTex format (requires biblatex-software package)
Generating citation ...
#!/usr/bin/env python

#
# Kuroga, single python file meta-build system for ninja
# https://github.com/lighttransport/kuroga
#
# Requirements: python 2.6 or 2.7
#
# Usage: $ python kuroga.py input.py
#

import imp
import re
import textwrap
import glob
import os
import sys

# gcc preset
def add_gnu_rule(ninja):
    ninja.rule('gnucxx', description='CXX $out',
        command='$gnucxx -MMD -MF $out.d $gnudefines $gnuincludes $gnucxxflags -c $in -o $out',
        depfile='$out.d', deps='gcc')
    ninja.rule('gnucc', description='CC $out',
        command='$gnucc -MMD -MF $out.d $gnudefines $gnuincludes $gnucflags -c $in -o $out',
        depfile='$out.d', deps='gcc')
    ninja.rule('gnulink', description='LINK $out', pool='link_pool',
        command='$gnuld -o $out $in $libs $gnuldflags')
    ninja.rule('gnuar', description='AR $out', pool='link_pool',
        command='$gnuar rsc $out $in')
    ninja.rule('gnustamp', description='STAMP $out', command='touch $out')
    ninja.newline()

    ninja.variable('gnucxx', 'g++')
    ninja.variable('gnucc', 'gcc')
    ninja.variable('gnuld', '$gnucxx')
    ninja.variable('gnuar', 'ar')
    ninja.newline()

# clang preset
def add_clang_rule(ninja):
    ninja.rule('clangcxx', description='CXX $out',
        command='$clangcxx -MMD -MF $out.d $clangdefines $clangincludes $clangcxxflags -c $in -o $out',
        depfile='$out.d', deps='gcc')
    ninja.rule('clangcc', description='CC $out',
        command='$clangcc -MMD -MF $out.d $clangdefines $clangincludes $clangcflags -c $in -o $out',
        depfile='$out.d', deps='gcc')
    ninja.rule('clanglink', description='LINK $out', pool='link_pool',
        command='$clangld -o $out $in $libs $gnuldflags')
    ninja.rule('clangar', description='AR $out', pool='link_pool',
        command='$clangar rsc $out $in')
    ninja.rule('clangstamp', description='STAMP $out', command='touch $out')
    ninja.newline()

    ninja.variable('clangcxx', 'clang++')
    ninja.variable('clangcc', 'clang')
    ninja.variable('clangld', '$clangcxx')
    ninja.variable('clangar', 'ar')
    ninja.newline()

# msvc preset
def add_msvc_rule(ninja):
    ninja.rule('msvccxx', description='CXX $out',
        command='$msvccxx /TP /showIncludes $msvcdefines $msvcincludes $msvccxxflags -c $in /Fo$out',
        depfile='$out.d', deps='msvc')
    ninja.rule('msvccc', description='CC $out',
        command='$msvccc /TC /showIncludes $msvcdefines $msvcincludes $msvccflags -c $in /Fo$out',
        depfile='$out.d', deps='msvc')
    ninja.rule('msvclink', description='LINK $out', pool='link_pool',
        command='$msvcld $msvcldflags $in $libs /OUT:$out')
    ninja.rule('msvcar', description='AR $out', pool='link_pool',
        command='$msvcar $in /OUT:$out')
    #ninja.rule('msvcstamp', description='STAMP $out', command='touch $out')
    ninja.newline()

    ninja.variable('msvccxx', 'cl.exe')
    ninja.variable('msvccc', 'cl.exe')
    ninja.variable('msvcld', 'link.exe')
    ninja.variable('msvcar', 'lib.exe')
    ninja.newline()

# -- from ninja_syntax.py --
def escape_path(word):
    return word.replace('$ ', '$$ ').replace(' ', '$ ').replace(':', '$:')

class Writer(object):
    def __init__(self, output, width=78):
        self.output = output
        self.width = width

    def newline(self):
        self.output.write('\n')

    def comment(self, text, has_path=False):
        for line in textwrap.wrap(text, self.width - 2, break_long_words=False,
                                  break_on_hyphens=False):
            self.output.write('# ' + line + '\n')

    def variable(self, key, value, indent=0):
        if value is None:
            return
        if isinstance(value, list):
            value = ' '.join(filter(None, value))  # Filter out empty strings.
        self._line('%s = %s' % (key, value), indent)

    def pool(self, name, depth):
        self._line('pool %s' % name)
        self.variable('depth', depth, indent=1)

    def rule(self, name, command, description=None, depfile=None,
             generator=False, pool=None, restat=False, rspfile=None,
             rspfile_content=None, deps=None):
        self._line('rule %s' % name)
        self.variable('command', command, indent=1)
        if description:
            self.variable('description', description, indent=1)
        if depfile:
            self.variable('depfile', depfile, indent=1)
        if generator:
            self.variable('generator', '1', indent=1)
        if pool:
            self.variable('pool', pool, indent=1)
        if restat:
            self.variable('restat', '1', indent=1)
        if rspfile:
            self.variable('rspfile', rspfile, indent=1)
        if rspfile_content:
            self.variable('rspfile_content', rspfile_content, indent=1)
        if deps:
            self.variable('deps', deps, indent=1)

    def build(self, outputs, rule, inputs=None, implicit=None, order_only=None,
              variables=None):
        outputs = as_list(outputs)
        out_outputs = [escape_path(x) for x in outputs]
        all_inputs = [escape_path(x) for x in as_list(inputs)]

        if implicit:
            implicit = [escape_path(x) for x in as_list(implicit)]
            all_inputs.append('|')
            all_inputs.extend(implicit)
        if order_only:
            order_only = [escape_path(x) for x in as_list(order_only)]
            all_inputs.append('||')
            all_inputs.extend(order_only)

        self._line('build %s: %s' % (' '.join(out_outputs),
                                     ' '.join([rule] + all_inputs)))

        if variables:
            if isinstance(variables, dict):
                iterator = iter(variables.items())
            else:
                iterator = iter(variables)

            for key, val in iterator:
                self.variable(key, val, indent=1)

        return outputs

    def include(self, path):
        self._line('include %s' % path)

    def subninja(self, path):
        self._line('subninja %s' % path)

    def default(self, paths):
        self._line('default %s' % ' '.join(as_list(paths)))

    def _count_dollars_before_index(self, s, i):
        """Returns the number of '$' characters right in front of s[i]."""
        dollar_count = 0
        dollar_index = i - 1
        while dollar_index > 0 and s[dollar_index] == '$':
            dollar_count += 1
            dollar_index -= 1
        return dollar_count

    def _line(self, text, indent=0):
        """Write 'text' word-wrapped at self.width characters."""
        leading_space = '  ' * indent
        while len(leading_space) + len(text) > self.width:
            # The text is too wide; wrap if possible.

            # Find the rightmost space that would obey our width constraint and
            # that's not an escaped space.
            available_space = self.width - len(leading_space) - len(' $')
            space = available_space
            while True:
                space = text.rfind(' ', 0, space)
                if (space < 0 or
                    self._count_dollars_before_index(text, space) % 2 == 0):
                    break

            if space < 0:
                # No such space; just use the first unescaped space we can find.
                space = available_space - 1
                while True:
                    space = text.find(' ', space + 1)
                    if (space < 0 or
                        self._count_dollars_before_index(text, space) % 2 == 0):
                        break
            if space < 0:
                # Give up on breaking.
                break

            self.output.write(leading_space + text[0:space] + ' $\n')
            text = text[space+1:]

            # Subsequent lines are continuations, so indent them.
            leading_space = '  ' * (indent+2)

        self.output.write(leading_space + text + '\n')

    def close(self):
        self.output.close()


def as_list(input):
    if input is None:
        return []
    if isinstance(input, list):
        return input
    return [input]

# -- end from ninja_syntax.py --

def gen(ninja, toolchain, config):
    
    ninja.variable('ninja_required_version', '1.4')
    ninja.newline()

    if hasattr(config, "builddir"):
        builddir = config.builddir[toolchain]
        ninja.variable(toolchain + 'builddir', builddir)
    else:
        builddir = ''

    ninja.variable(toolchain + 'defines', config.defines[toolchain] or [])
    ninja.variable(toolchain + 'includes', config.includes[toolchain] or [])
    ninja.variable(toolchain + 'cflags', config.cflags[toolchain] or [])
    ninja.variable(toolchain + 'cxxflags', config.cxxflags[toolchain] or [])
    ninja.variable(toolchain + 'ldflags', config.ldflags[toolchain] or [])
    ninja.newline()

    if hasattr(config, "link_pool_depth"):
        ninja.pool('link_pool', depth=config.link_pool_depth)
    else:
        ninja.pool('link_pool', depth=4)
    ninja.newline()

    # Add default toolchain(gnu, clang and msvc)
    add_gnu_rule(ninja)
    add_clang_rule(ninja)
    add_msvc_rule(ninja)

    obj_files = []

    cc = toolchain + 'cc'
    cxx = toolchain + 'cxx'
    link = toolchain + 'link'
    ar = toolchain + 'ar'
    
    if hasattr(config, "cxx_files"):
        for src in config.cxx_files:
            srcfile = src
            obj = os.path.splitext(srcfile)[0] + '.o'
            obj = os.path.join(builddir, obj);
            obj_files.append(obj)
            ninja.build(obj, cxx, srcfile)
        ninja.newline()

    if hasattr(config, "c_files"):
        for src in config.c_files:
            srcfile = src
            obj = os.path.splitext(srcfile)[0] + '.o'
            obj = os.path.join(builddir, obj);
            obj_files.append(obj)
            ninja.build(obj, cc, srcfile)
        ninja.newline()

    targetlist = []
    if hasattr(config, "exe"):
        ninja.build(config.exe, link, obj_files)
        targetlist.append(config.exe)

    if hasattr(config, "staticlib"):
        ninja.build(config.staticlib, ar, obj_files)
        targetlist.append(config.staticlib)

    ninja.build('all', 'phony', targetlist)
    ninja.newline()
        
    ninja.default('all')

def main():
    if len(sys.argv) < 2:
        print("Usage: python kuroga.py config.py")
        sys.exit(1)

    config = imp.load_source("config", sys.argv[1])

    f = open('build.ninja', 'w')
    ninja = Writer(f)

    if hasattr(config, "register_toolchain"):
        config.register_toolchain(ninja)
        
    gen(ninja, config.toolchain, config)
    f.close()

main()

back to top

Software Heritage — Copyright (C) 2015–2026, The Software Heritage developers. License: GNU AGPLv3+.
The source code of Software Heritage itself is available on our development forge.
The source code files archived by Software Heritage are available under their own copyright and licenses.
Terms of use: Archive access, API— Content policy— Contact— JavaScript license information— Web API