<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def bootstrap_c_source(scheduler_bindings_path, output_dir, module_name=NATIVE_ENGINE_MODULE):
 """Bootstrap an external CFFI C source file."""


  safe_mkdir(output_dir)

  with temporary_dir() as tempdir:
    temp_output_prefix = os.path.join(tempdir, module_name)
    real_output_prefix = os.path.join(output_dir, module_name)
    temp_c_file = '{}.c'.format(temp_output_prefix)
    if PY2:
      temp_c_file = temp_c_file.encode('utf-8')
    c_file = '{}.c'.format(real_output_prefix)
    env_script = '{}.cflags'.format(real_output_prefix)

    # Preprocessor directives won't parse in the .cdef calls, so we have to hide them for now.
    scheduler_bindings_content = read_file(scheduler_bindings_path)
    scheduler_bindings = _hackily_rewrite_scheduler_bindings(scheduler_bindings_content)

    ffibuilder = cffi.FFI()
    ffibuilder.cdef(scheduler_bindings)
    ffibuilder.cdef(_FFISpecification.format_cffi_externs())
    ffibuilder.set_source(module_name, scheduler_bindings)
    ffibuilder.emit_c_code(temp_c_file)

    # Work around https://github.com/rust-lang/rust/issues/36342 by renaming initnative_engine to
    # wrapped_initnative_engine so that the rust code can define the symbol initnative_engine.
    #
    # If we dont do this, we end up at the mercy of the implementation details of rust's stripping
    # and LTO. In the past we have found ways to trick it into not stripping symbols which was handy
    # (it kept the binary working) but inconvenient (it was relying on unspecified behavior, it meant
    # our binaries couldn't be stripped which inflated them by 2~3x, and it reduced the amount of LTO
    # we could use, which led to unmeasured performance hits).
    #
    # We additionally remove the ifdefs that apply conditional `init` logic for Py2 vs Py3, in order
    # to define a module that is loadable by either 2 or 3.
    # TODO: Because PyPy uses the same `init` function name regardless of the python version, this
    # trick does not work there: we leave its conditional in place.
    file_content = read_file(temp_c_file)
    if CFFI_C_PATCH_BEFORE not in file_content:
      raise Exception('The patch for the CFFI generated code will not apply cleanly.')
    file_content = file_content.replace(CFFI_C_PATCH_BEFORE, CFFI_C_PATCH_AFTER)

    # Extract the preprocessor directives we had to hide to get the .cdef call to parse.
    file_content = _hackily_recreate_includes_for_bindings(file_content)

  _replace_file(c_file, file_content)

  # Write a shell script to be sourced at build time that contains inherited CFLAGS.
  _replace_file(env_script, get_build_cflags())