<commit_before>

from typing import List, Dict, Union, Callable, Type
import functools
import logging as log
import nodepy
import re
import sys

import craftr from 'craftr'
import utils, {stream.concat as concat, stream.unique as unique} from 'craftr/utils'
import path from 'craftr/utils/path'
import macro from 'craftr/utils/macro'
import path from 'craftr/utils/path'


def infer_linkage(target):
  choices = set()
  for build in target.dependents(with_behaviour=CxxBuild).attr('impl'):
    choices.add(build.link_style)
  if len(choices) > 1:
    log.warn('Target "{}" has preferred_linkage=any, but dependents '
      'specify conflicting link_styles {}. Falling back to static.'
      .format(target.long_name, choices))
    preferred_linkage = 'static'
  elif len(choices) == 1:
    preferred_linkage = choices.pop()
  else:
    preferred_linkage = craftr.options.get('cxx.preferred_linkage', 'static')
    if preferred_linkage not in ('static', 'shared'):
      raise RuntimeError('invalid cxx.preferred_linkage option: {!r}'
        .format(preferred_linkage))
  return preferred_linkage


def infer_bool(target, attr, default):
  for build in target.dependents(with_behaviour=CxxBuild).attr('impl'):
    if getattr(build, attr):
      return True
  else:
    return default


def infer_optimize(target):
  for build in target.dependents(with_behaviour=CxxBuild).attr('impl'):
    if build.optimize:
      return build.optimize
  return craftr.options.get('cxx.optimize', 'speed')


class CxxBuild(craftr.Behaviour):

  def init(self,
        type: str,
        srcs: List[str] = None,
        c_std = None,
        cpp_std = None,
        debug: bool = None,
        warnings: bool = True,
        warnings_as_errors: bool = False,
        optimize: str = None,
        static_defines: List[str] = None,
        exported_static_defines: List[str] = None,
        shared_defines: List[str] = None,
        exported_shared_defines: List[str] = None,
        includes: List[str] = None,
        exported_includes: List[str] = None,
        defines: List[str] = None,
        exported_defines: List[str] = None,
        compiler_flags: List[str] = None,
        exported_compiler_flags: List[str] = None,
        linker_flags: List[str] = None,
        exported_linker_flags: List[str] = None,
        syslibs: List[str] = None,
        exported_syslibs: List[str] = None,
        link_style: str = None,
        preferred_linkage: str = 'any',
        static_runtime: bool = None,
        outname: str = '$(lib)$(name)$(ext)',
        outdir: str = NotImplemented,
        unity_build: bool = None,
        compiler: 'Compiler' = None,
        options: Dict = None,
        localize_srcs: bool = True):
    if not compiler:
      compiler = globals()['compiler']
    if type not in ('library', 'binary'):
      raise ValueError('invalid type: {!r}'.format(type))
    if optimize not in (None, 'speed', 'size'):
      raise ValueError('invalid value for optimize: {!r}'.format(optimize))
    if not link_style:
      link_style = craftr.options.get('cxx.link_style', 'static')
    if link_style not in ('static', 'shared'):
      raise ValueError('invalid link_style: {!r}'.format(link_style))
    if preferred_linkage not in ('any', 'static', 'shared'):
      raise ValueError('invalid preferred_linkage: {!r}'.format(preferred_linkage))
    if isinstance(srcs, str):
      srcs = [srcs]
    if options is None:
      options = {}
    if isinstance(options, dict):
      options = compiler.options_class(**options)
    if not isinstance(options, compiler.options_class):
      raise TypeError('options must be None, dict or {}, got {} instead'
        .format(compilre.options_class.__name__, type(options).__name__))
    self.srcs = [craftr.localpath(x) for x in (srcs or [])] if localize_srcs else (srcs or [])
    if not self.srcs:
      raise ValueError('srcs must have minimum length 1')
    if outdir is NotImplemented:
      outdir = self.namespace.build_directory
    self.type = type
    self.debug = debug
    self.c_std = c_std
    self.cpp_std = cpp_std
    self.warnings = warnings
    self.warnings_as_errors = warnings_as_errors
    self.optimize = optimize
    self.static_defines = static_defines or []
    self.exported_static_defines = exported_static_defines or []
    self.shared_defines = shared_defines or []
    self.exported_shared_defines = exported_shared_defines or []
    self.includes = [craftr.localpath(x) for x in (includes or [])]
    self.exported_includes = [craftr.localpath(x) for x in (exported_includes or [])]
    self.defines = defines or []
    self.exported_defines = exported_defines or []
    self.compiler_flags = compiler_flags or []
    self.exported_compiler_flags = exported_compiler_flags or []
    self.linker_flags = linker_flags or []
    self.exported_linker_flags = exported_linker_flags or []
    self.syslibs = syslibs or []
    self.exported_syslibs = exported_syslibs or []
    self.link_style = link_style
    self.preferred_linkage = preferred_linkage
    self.static_runtime = static_runtime
    self.outname = outname
    self.outdir = outdir
    self.unity_build = unity_build
    self.compiler = compiler
    self.options = options
    self.additional_outputs = []

    if self.is_foreach():
      if len(outname) != len(self.srcs):
        raise ValueError('if outname is a list, it must have the same length as srcs')
    elif not isinstance(self.outname, str):
      raise ValueError('outname must be a list or str')

    if self.unity_build is None:
      if self.is_foreach():
        self.unity_build = False
      else:
        unity_build = bool(craftr.options.get('cxx.unity_build', False))
    elif self.unity_build and self.is_foreach():
      raise ValueError('unity_build can not be combined with foreach build target')

    # Set after translate().
    self.outname_full = None
    # Required for MSVC because the file to link with is different
    # than the actual output DLL output file.
    self.linkname_full = None

    if self.options.__unknown_options__:
      log.warn('[{}]: Unknown compiler option(s): {}'.format(
        target.long_name, ', '.join(self.options.__unknown_options__.keys())))

  def is_foreach(self):
    return isinstance(self.outname, list)

  def is_staticlib(self):
    return self.type == 'library' and self.preferred_linkage == 'static'

  def is_sharedlib(self):
    return self.type == 'library' and self.preferred_linkage == 'shared'

  def is_binary(self):
    return self.type == 'binary'

  def has_cpp_sources(self):
    for fname in self.srcs:
      if fname.endswith('.cpp') or fname.endswith('.cc'):
        return True
    return False

  def translate(self):
    # Update the preferred linkage of this target.
    if self.preferred_linkage == 'any':
      self.preferred_linkage = infer_linkage(self.target)
    assert self.preferred_linkage in ('static', 'shared')

    # Inherit the debug option if it is not set.
    # XXX What do to on different values?
    if self.debug is None:
      self.debug = infer_bool(self.target, 'debug', not craftr.is_release)

    # Inherit static runtime property.
    if self.static_runtime is None:
      self.static_runtime = infer_bool(self.target, 'static_runtime',
          craftr.options.get('cxx.static_runtime', False))

    # Inherit the optimize flag if it is not set.
    # XXX What do to on different values?
    if self.optimize is None:
      self.optimize = infer_optimize(self.target)
    if self.optimize not in ('speed', 'size'):
      raise RuntimeError('[{}] invalid optimize: {!r}'.format(
        self.target.long_name, self.optimize))

    # Separate C and C++ sources.
    c_srcs = []
    cpp_srcs = []
    unknown = []
    for src in self.srcs:
      if src.endswith('.cpp') or src.endswith('.cc'):
        cpp_srcs.append(src)
      elif src.endswith('.c'):
        c_srcs.append(src)
      else:
        unknown.append(src)
    if unknown:
      if c_srcs or not cpp_srcs:
        c_srcs.extend(unknown)
      else:
        cpp_srcs.extend(unknown)
<commit_msg>cxx.static_runtime falls back based on whether the CxxBuild target has link_style==static<commit_after>

from typing import List, Dict, Union, Callable, Type
import functools
import logging as log
import nodepy
import re
import sys

import craftr from 'craftr'
import utils, {stream.concat as concat, stream.unique as unique} from 'craftr/utils'
import path from 'craftr/utils/path'
import macro from 'craftr/utils/macro'
import path from 'craftr/utils/path'


def infer_linkage(target):
  choices = set()
  for build in target.dependents(with_behaviour=CxxBuild).attr('impl'):
    choices.add(build.link_style)
  if len(choices) > 1:
    log.warn('Target "{}" has preferred_linkage=any, but dependents '
      'specify conflicting link_styles {}. Falling back to static.'
      .format(target.long_name, choices))
    preferred_linkage = 'static'
  elif len(choices) == 1:
    preferred_linkage = choices.pop()
  else:
    preferred_linkage = craftr.options.get('cxx.preferred_linkage', 'static')
    if preferred_linkage not in ('static', 'shared'):
      raise RuntimeError('invalid cxx.preferred_linkage option: {!r}'
        .format(preferred_linkage))
  return preferred_linkage


def infer_bool(target, attr, default):
  for build in target.dependents(with_behaviour=CxxBuild).attr('impl'):
    if getattr(build, attr):
      return True
  else:
    return default


def infer_optimize(target):
  for build in target.dependents(with_behaviour=CxxBuild).attr('impl'):
    if build.optimize:
      return build.optimize
  return craftr.options.get('cxx.optimize', 'speed')


class CxxBuild(craftr.Behaviour):

  def init(self,
        type: str,
        srcs: List[str] = None,
        c_std = None,
        cpp_std = None,
        debug: bool = None,
        warnings: bool = True,
        warnings_as_errors: bool = False,
        optimize: str = None,
        static_defines: List[str] = None,
        exported_static_defines: List[str] = None,
        shared_defines: List[str] = None,
        exported_shared_defines: List[str] = None,
        includes: List[str] = None,
        exported_includes: List[str] = None,
        defines: List[str] = None,
        exported_defines: List[str] = None,
        compiler_flags: List[str] = None,
        exported_compiler_flags: List[str] = None,
        linker_flags: List[str] = None,
        exported_linker_flags: List[str] = None,
        syslibs: List[str] = None,
        exported_syslibs: List[str] = None,
        link_style: str = None,
        preferred_linkage: str = 'any',
        static_runtime: bool = None,
        outname: str = '$(lib)$(name)$(ext)',
        outdir: str = NotImplemented,
        unity_build: bool = None,
        compiler: 'Compiler' = None,
        options: Dict = None,
        localize_srcs: bool = True):
    if not compiler:
      compiler = globals()['compiler']
    if type not in ('library', 'binary'):
      raise ValueError('invalid type: {!r}'.format(type))
    if optimize not in (None, 'speed', 'size'):
      raise ValueError('invalid value for optimize: {!r}'.format(optimize))
    if not link_style:
      link_style = craftr.options.get('cxx.link_style', 'static')
    if link_style not in ('static', 'shared'):
      raise ValueError('invalid link_style: {!r}'.format(link_style))
    if preferred_linkage not in ('any', 'static', 'shared'):
      raise ValueError('invalid preferred_linkage: {!r}'.format(preferred_linkage))
    if isinstance(srcs, str):
      srcs = [srcs]
    if options is None:
      options = {}
    if isinstance(options, dict):
      options = compiler.options_class(**options)
    if not isinstance(options, compiler.options_class):
      raise TypeError('options must be None, dict or {}, got {} instead'
        .format(compilre.options_class.__name__, type(options).__name__))
    self.srcs = [craftr.localpath(x) for x in (srcs or [])] if localize_srcs else (srcs or [])
    if not self.srcs:
      raise ValueError('srcs must have minimum length 1')
    if outdir is NotImplemented:
      outdir = self.namespace.build_directory
    self.type = type
    self.debug = debug
    self.c_std = c_std
    self.cpp_std = cpp_std
    self.warnings = warnings
    self.warnings_as_errors = warnings_as_errors
    self.optimize = optimize
    self.static_defines = static_defines or []
    self.exported_static_defines = exported_static_defines or []
    self.shared_defines = shared_defines or []
    self.exported_shared_defines = exported_shared_defines or []
    self.includes = [craftr.localpath(x) for x in (includes or [])]
    self.exported_includes = [craftr.localpath(x) for x in (exported_includes or [])]
    self.defines = defines or []
    self.exported_defines = exported_defines or []
    self.compiler_flags = compiler_flags or []
    self.exported_compiler_flags = exported_compiler_flags or []
    self.linker_flags = linker_flags or []
    self.exported_linker_flags = exported_linker_flags or []
    self.syslibs = syslibs or []
    self.exported_syslibs = exported_syslibs or []
    self.link_style = link_style
    self.preferred_linkage = preferred_linkage
    self.static_runtime = static_runtime
    self.outname = outname
    self.outdir = outdir
    self.unity_build = unity_build
    self.compiler = compiler
    self.options = options
    self.additional_outputs = []

    if self.is_foreach():
      if len(outname) != len(self.srcs):
        raise ValueError('if outname is a list, it must have the same length as srcs')
    elif not isinstance(self.outname, str):
      raise ValueError('outname must be a list or str')

    if self.unity_build is None:
      if self.is_foreach():
        self.unity_build = False
      else:
        unity_build = bool(craftr.options.get('cxx.unity_build', False))
    elif self.unity_build and self.is_foreach():
      raise ValueError('unity_build can not be combined with foreach build target')

    # Set after translate().
    self.outname_full = None
    # Required for MSVC because the file to link with is different
    # than the actual output DLL output file.
    self.linkname_full = None

    if self.options.__unknown_options__:
      log.warn('[{}]: Unknown compiler option(s): {}'.format(
        target.long_name, ', '.join(self.options.__unknown_options__.keys())))

  def is_foreach(self):
    return isinstance(self.outname, list)

  def is_staticlib(self):
    return self.type == 'library' and self.preferred_linkage == 'static'

  def is_sharedlib(self):
    return self.type == 'library' and self.preferred_linkage == 'shared'

  def is_binary(self):
    return self.type == 'binary'

  def has_cpp_sources(self):
    for fname in self.srcs:
      if fname.endswith('.cpp') or fname.endswith('.cc'):
        return True
    return False

  def translate(self):
    # Update the preferred linkage of this target.
    if self.preferred_linkage == 'any':
      self.preferred_linkage = infer_linkage(self.target)
    assert self.preferred_linkage in ('static', 'shared')

    # Inherit the debug option if it is not set.
    # XXX What do to on different values?
    if self.debug is None:
      self.debug = infer_bool(self.target, 'debug', not craftr.is_release)

    # Inherit static runtime property.
    if self.static_runtime is None:
      self.static_runtime = infer_bool(self.target, 'static_runtime',
          craftr.options.get('cxx.static_runtime', self.link_style == 'static'))

    # Inherit the optimize flag if it is not set.
    # XXX What do to on different values?
    if self.optimize is None:
      self.optimize = infer_optimize(self.target)
    if self.optimize not in ('speed', 'size'):
      raise RuntimeError('[{}] invalid optimize: {!r}'.format(
        self.target.long_name, self.optimize))

    # Separate C and C++ sources.
    c_srcs = []
    cpp_srcs = []
    unknown = []
    for src in self.srcs:
      if src.endswith('.cpp') or src.endswith('.cc'):
        cpp_srcs.append(src)
      elif src.endswith('.c'):
        c_srcs.append(src)
      else:
        unknown.append(src)
    if unknown:
      if c_srcs or not cpp_srcs:
        c_srcs.extend(unknown)
      else:
        cpp_srcs.extend(unknown)

{'fraction_non_alphanumeric': 0.1108781450419339, 'fraction_numerical': 0.00037000493339911197, 'mean_word_length': 3.1958602846054336, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4592491', 'n_tokens_mistral': 5189, 'n_tokens_neox': 5068, 'n_words': 1351}