Top Banner
Modules Doug Gregor, Apple Wednesday, November 7, 12
87

Gregor modules

Nov 29, 2014

Download

Documents

skyshaw

 
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Gregor modules

ModulesDoug Gregor, Apple

Wednesday, November 7, 12

Page 2: Gregor modules

Roadmap

• The fundamental brokenness of headers

• A module system for the C family

• Building better tools

Wednesday, November 7, 12

Page 3: Gregor modules

On the Fundamental Brokenness of Headers

Wednesday, November 7, 12

Page 4: Gregor modules

#include <stdio.h>

int main() { printf(“Hello, world!\n”);}

C Preprocessing Model

Wednesday, November 7, 12

Page 5: Gregor modules

#include <stdio.h>

int main() { printf(“Hello, world!\n”);}

C Preprocessing Model// stdio.h

typedef struct { ...} FILE;

int printf(const char*, ...);int fprintf(FILE *, const char*, ...);int remove(const char*);

// on and on...

Wednesday, November 7, 12

Page 6: Gregor modules

#include <stdio.h>

int main() { printf(“Hello, world!\n”);}

C Preprocessing Model// stdio.h

typedef struct { ...} FILE;

int printf(const char*, ...);int fprintf(FILE *, const char*, ...);int remove(const char*);

// on and on...

Wednesday, November 7, 12

Page 7: Gregor modules

// from stdio.h

typedef struct { ...} FILE;

int printf(const char*, ...);int fprintf(FILE *, const char*, ...);int remove(const char*);

// on and on...

int main() { printf(“Hello, world!\n”);}

C Preprocessing Model

Wednesday, November 7, 12

Page 8: Gregor modules

// from stdio.h

typedef struct { ...} FILE;

int printf(const char*, ...);int fprintf(FILE *, const char*, ...);int remove(const char*);

// on and on...

int main() { printf(“Hello, world!\n”);}

Problems with the Model

• Fragility

• Performance

Wednesday, November 7, 12

Page 9: Gregor modules

#define FILE “MyFile.txt”#include <stdio.h>

int main() { printf(“Hello, world!\n”);}

Header Fragility

Wednesday, November 7, 12

Page 10: Gregor modules

#define FILE “MyFile.txt”#include <stdio.h>

int main() { printf(“Hello, world!\n”);}

Header Fragility// stdio.h

typedef struct { ...} FILE;

int printf(const char*, ...);int fprintf(FILE *, const char*, ...);int remove(const char*);

// on and on...

Wednesday, November 7, 12

Page 11: Gregor modules

#define FILE “MyFile.txt”#include <stdio.h>

int main() { printf(“Hello, world!\n”);}

Header Fragility// stdio.h

typedef struct { ...} FILE;

int printf(const char*, ...);int fprintf(FILE *, const char*, ...);int remove(const char*);

// on and on...

Wednesday, November 7, 12

Page 12: Gregor modules

// from stdio.h

typedef struct { ...} “MyFile.txt”;

int printf(const char*, ...);int fprintf(“MyFile.txt” *, const char*, ...);int remove(const char*);

// on and on...

int main() { printf(“Hello, world!\n”);}

Header Fragility

Wednesday, November 7, 12

Page 13: Gregor modules

Conventional Workarounds

Wednesday, November 7, 12

Page 14: Gregor modules

Conventional Workarounds

• LLVM_WHY_PREFIX_UPPER_MACROS

Wednesday, November 7, 12

Page 15: Gregor modules

Conventional Workarounds

• LLVM_WHY_PREFIX_UPPER_MACROS

• LLVM_CLANG_INCLUDE_GUARD_H

Wednesday, November 7, 12

Page 16: Gregor modules

Conventional Workarounds

• LLVM_WHY_PREFIX_UPPER_MACROS

• LLVM_CLANG_INCLUDE_GUARD_H

• template<class _Tp>const _Tp& min(const _Tp &__a, const _Tp &__b);

Wednesday, November 7, 12

Page 17: Gregor modules

Conventional Workarounds

• LLVM_WHY_PREFIX_UPPER_MACROS

• LLVM_CLANG_INCLUDE_GUARD_H

• template<class _Tp>const _Tp& min(const _Tp &__a, const _Tp &__b);

• #include <windows.h>#undef min // because #define NOMINMAX#undef max // doesn’t always work

Wednesday, November 7, 12

Page 18: Gregor modules

How Big is a Source File?

Wednesday, November 7, 12

Page 19: Gregor modules

How Big is a Source File?#include <stdio.h>

int main() { printf(“Hello, world!\n”);}

Wednesday, November 7, 12

Page 20: Gregor modules

How Big is a Source File?#include <stdio.h>

int main() { printf(“Hello, world!\n”);}

Source

Headers

C Hello C++ Hello SemaOverload

64 81 469,939

11,072 1,161,033 3,824,521

Wednesday, November 7, 12

Page 21: Gregor modules

How Big is a Source File?#include <stdio.h>

int main() { printf(“Hello, world!\n”);}

Source

Headers

C Hello C++ Hello SemaOverload

64 81 469,939

11,072 1,161,033 3,824,521

#include <iostream>

int main() { std::cout << “Hello, world!” << std::endl;}

Wednesday, November 7, 12

Page 22: Gregor modules

How Big is a Source File?#include <stdio.h>

int main() { printf(“Hello, world!\n”);}

Source

Headers

C Hello C++ Hello SemaOverload

64 81 469,939

11,072 1,161,033 3,824,521

#include <iostream>

int main() { std::cout << “Hello, world!” << std::endl;}

Wednesday, November 7, 12

Page 23: Gregor modules

How Big is a Source File?#include <stdio.h>

int main() { printf(“Hello, world!\n”);}

Source

Headers

C Hello C++ Hello SemaOverload

64 81 469,939

11,072 1,161,033 3,824,521

#include <iostream>

int main() { std::cout << “Hello, world!” << std::endl;}

Wednesday, November 7, 12

Page 24: Gregor modules

Inherently Non-Scalable

• M headers with N source files

• M x N build cost

• C++ templates exacerbate the problem

• Precompiled headers are a terrible solution

Wednesday, November 7, 12

Page 25: Gregor modules

A Module System for the C Family

Wednesday, November 7, 12

Page 26: Gregor modules

What Is a Module?

• A module is a package describing a library

• Interface of the library (API)

• Implementation of the library

Wednesday, November 7, 12

Page 27: Gregor modules

Module Imports

• ‘import’ makes the API of the named module available

import std;

int main() { printf(“Hello, World!\n”);}

Wednesday, November 7, 12

Page 28: Gregor modules

Module Imports

• ‘import’ makes the API of the named module available

import std;

int main() { printf(“Hello, World!\n”);}

// std module (includes stdio)

typedef struct { ...} FILE;

int printf(const char*, ...);int fprintf(FILE *, const char*, ...);int remove(const char*);

// on and on...

Wednesday, November 7, 12

Page 29: Gregor modules

Module Imports

• ‘import’ makes the API of the named module available

import std;

int main() { printf(“Hello, World!\n”);}

// std module (includes stdio)

typedef struct { ...} FILE;

int printf(const char*, ...);int fprintf(FILE *, const char*, ...);int remove(const char*);

// on and on...

Wednesday, November 7, 12

Page 30: Gregor modules

Import Resilience

• ‘import’ ignores preprocessor state within the source file

Wednesday, November 7, 12

Page 31: Gregor modules

Import Resilience

• ‘import’ ignores preprocessor state within the source file

#define FILE “MyFile.txt”import std;

int main() { printf(“Hello, World!\n”);}

Wednesday, November 7, 12

Page 32: Gregor modules

Import Resilience

• ‘import’ ignores preprocessor state within the source file

#define FILE “MyFile.txt”import std;

int main() { printf(“Hello, World!\n”);}

// std module (includes stdio)

typedef struct { ...} FILE;

int printf(const char*, ...);int fprintf(FILE *, const char*, ...);int remove(const char*);

// on and on...

Wednesday, November 7, 12

Page 33: Gregor modules

Import Resilience

• ‘import’ ignores preprocessor state within the source file

#define FILE “MyFile.txt”import std;

int main() { printf(“Hello, World!\n”);}

// std module (includes stdio)

typedef struct { ...} FILE;

int printf(const char*, ...);int fprintf(FILE *, const char*, ...);int remove(const char*);

// on and on...

Wednesday, November 7, 12

Page 34: Gregor modules

Selective Import// std module

// stdio submodule

typedef struct { ...} FILE;

int printf(const char*, ...);int fprintf(FILE *, const char*, ...);int remove(const char*);

// on and on...

// stdlib submodule

void abort(void);int rand(void);

// on and on...

Wednesday, November 7, 12

Page 35: Gregor modules

Selective Importimport std.stdio;

int main() { printf(“Hello, World!\n”);}

// std module

// stdio submodule

typedef struct { ...} FILE;

int printf(const char*, ...);int fprintf(FILE *, const char*, ...);int remove(const char*);

// on and on...

// stdlib submodule

void abort(void);int rand(void);

// on and on...

Wednesday, November 7, 12

Page 36: Gregor modules

Selective Importimport std.stdio;

int main() { printf(“Hello, World!\n”);}

// std module

// stdio submodule

typedef struct { ...} FILE;

int printf(const char*, ...);int fprintf(FILE *, const char*, ...);int remove(const char*);

// on and on...

// stdlib submodule

void abort(void);int rand(void);

// on and on...

Wednesday, November 7, 12

Page 37: Gregor modules

What Does import Import?

• Functions, variables, types, templates, macros, etc.

• Only public API -- everything else can be hidden.

• No special namespace mechanism.

Wednesday, November 7, 12

Page 38: Gregor modules

Writing a ModuleFuturistic Version

Wednesday, November 7, 12

Page 39: Gregor modules

Writing a Module

// stdio.cexport std.stdio:

public:typedef struct { ...} FILE;

int printf(const char*, ...) { // ...}

int fprintf(FILE *, const char*, ...) { // ...}

int remove(const char*) { // ...}

Wednesday, November 7, 12

Page 40: Gregor modules

Writing a Module

// stdio.cexport std.stdio:

public:typedef struct { ...} FILE;

int printf(const char*, ...) { // ...}

int fprintf(FILE *, const char*, ...) { // ...}

int remove(const char*) { // ...}

• Specify module name in source file

Wednesday, November 7, 12

Page 41: Gregor modules

Writing a Module

// stdio.cexport std.stdio:

public:typedef struct { ...} FILE;

int printf(const char*, ...) { // ...}

int fprintf(FILE *, const char*, ...) { // ...}

int remove(const char*) { // ...}

• Specify module name in source file

• Public access describes API

Wednesday, November 7, 12

Page 42: Gregor modules

Writing a Module

// stdio.cexport std.stdio:

public:typedef struct { ...} FILE;

int printf(const char*, ...) { // ...}

int fprintf(FILE *, const char*, ...) { // ...}

int remove(const char*) { // ...}

• Specify module name in source file

• Public access describes API

• No headers!

Wednesday, November 7, 12

Page 43: Gregor modules

Problems With This Future

• Transitioning existing header-based libraries

• Interoperability with compilers that don’t implement modules

• Requires tools that understand modules

Wednesday, November 7, 12

Page 44: Gregor modules

Writing a ModuleTransitional Version

Wednesday, November 7, 12

Page 45: Gregor modules

Embracing Headers

• Build modules directly from the headers

• Headers remain “the truth”

• Good for interoperability

• Doesn’t change the programmer model

Wednesday, November 7, 12

Page 46: Gregor modules

Module Maps// /usr/include/module.map

module std { module stdio { header “stdio.h” } module stdlib { header “stdlib.h” } module math { header “math.h” }}

• module defines a named (sub)module

• header includes the contents of the named header in the current (sub)module

Wednesday, November 7, 12

Page 47: Gregor modules

Umbrella Headers

• An umbrella header includes all of the headers in its directory

// clang/include/clang/module.map

module ClangAST { umbrella header “AST/AST.h” module * { }}

Wednesday, November 7, 12

Page 48: Gregor modules

Umbrella Headers

• An umbrella header includes all of the headers in its directory

• Wildcard submodules (module *) create a submodule for each included header

• AST/Decl.h -> ClangAST.Decl

• AST/Expr.h -> ClangAST.Expr

// clang/include/clang/module.map

module ClangAST { umbrella header “AST/AST.h” module * { }}

Wednesday, November 7, 12

Page 49: Gregor modules

Module Map Features

Wednesday, November 7, 12

Page 50: Gregor modules

Module Map Features

• Umbrella directoriesmodule LLVMADT { umbrella “llvm/ADT” module * { export * }}

Wednesday, November 7, 12

Page 51: Gregor modules

Module Map Features

• Umbrella directories

• Submodule requirements

module LLVMADT { umbrella “llvm/ADT” module * { export * }}

module _Builtin { module avx { requires avx header “avxintrin.h” }}

Wednesday, November 7, 12

Page 52: Gregor modules

Module Map Features

• Umbrella directories

• Submodule requirements

• Excluded headers

module LLVMADT { umbrella “llvm/ADT” module * { export * }}

module _Builtin { module avx { requires avx header “avxintrin.h” }}

module std { exclude header “assert.h”}

Wednesday, November 7, 12

Page 53: Gregor modules

Compilation Modelimport std.stdio;

int main() { printf(“Hello, World!\n”);}

Wednesday, November 7, 12

Page 54: Gregor modules

Compilation Model

1. Find a module map for the named module

import std.stdio;

int main() { printf(“Hello, World!\n”);}

Wednesday, November 7, 12

Page 55: Gregor modules

Compilation Model

1. Find a module map for the named module

2. Spawn a separate instance of the compiler:

• Parse the headers in the module map

• Write the module file

import std.stdio;

int main() { printf(“Hello, World!\n”);}

Wednesday, November 7, 12

Page 56: Gregor modules

Compilation Model

1. Find a module map for the named module

2. Spawn a separate instance of the compiler:

• Parse the headers in the module map

• Write the module file

3. Load the module file at the ‘import’ declaration

import std.stdio;

int main() { printf(“Hello, World!\n”);}

Wednesday, November 7, 12

Page 57: Gregor modules

Compilation Model

1. Find a module map for the named module

2. Spawn a separate instance of the compiler:

• Parse the headers in the module map

• Write the module file

3. Load the module file at the ‘import’ declaration

4. Cache module file for later re-use

import std.stdio;

int main() { printf(“Hello, World!\n”);}

Wednesday, November 7, 12

Page 58: Gregor modules

Adopting Modules: Libraries

• Eliminate non-modular behavior:

• Multiply-defined structs, functions, macros, must be consolidated

• Headers should import what they depend on

• Write module maps covering the library

Wednesday, November 7, 12

Page 59: Gregor modules

Adopting Modules: Users

#include <stdio.h>

int main() { printf(“Hello, World!\n”);}

Wednesday, November 7, 12

Page 60: Gregor modules

Adopting Modules: Users

• “Simply” rewrite each #include as an import

#include <stdio.h>

int main() { printf(“Hello, World!\n”);}

import std.stdio;

int main() { printf(“Hello, World!\n”);}

Wednesday, November 7, 12

Page 61: Gregor modules

Translating #include to import

import std.stdio;

int main() { printf(“Hello, World!\n”);}

#include <stdio.h>

int main() { printf(“Hello, World!\n”);}

Wednesday, November 7, 12

Page 62: Gregor modules

Translating #include to import

• Use module maps to determine (sub)module corresponding to an #include’d header

import std.stdio;

int main() { printf(“Hello, World!\n”);}

#include <stdio.h>

int main() { printf(“Hello, World!\n”);}

Wednesday, November 7, 12

Page 63: Gregor modules

Translating #include to import

• Use module maps to determine (sub)module corresponding to an #include’d header

• Optional Fix-Its, tooling to finalize the rewrite

import std.stdio;

int main() { printf(“Hello, World!\n”);}

#include <stdio.h>

int main() { printf(“Hello, World!\n”);}

Wednesday, November 7, 12

Page 64: Gregor modules

Translating #include to import

• Use module maps to determine (sub)module corresponding to an #include’d header

• Optional Fix-Its, tooling to finalize the rewrite

• Enabling modules is transparent to the user

import std.stdio;

int main() { printf(“Hello, World!\n”);}

#include <stdio.h>

int main() { printf(“Hello, World!\n”);}

Wednesday, November 7, 12

Page 65: Gregor modules

Building Better Tools(For the Future)

Wednesday, November 7, 12

Page 66: Gregor modules

Compilation Performance

• Algorithmic improvement for parsing time

• Module headers parsed once, cached

• M x N M + N

• Benefits for all source-based tools

Wednesday, November 7, 12

Page 67: Gregor modules

Automatic Linking

• Drastically simplifies use of a library

// clang/include/clang/module.map

module ClangAST { umbrella header “AST/AST.h” module * { } link “-lclangAST”}

Wednesday, November 7, 12

Page 68: Gregor modules

Automatic Import

• Forgotten #include terrible diagnostic

int main() { std::vector<int> v;}

Wednesday, November 7, 12

Page 69: Gregor modules

Automatic Import

• Forgotten #include terrible diagnostic

• vector.cpp:2:6: error: ‘vector‘ template is not available std::vector<int> v; ^note: import ‘std.vector‘ to use ‘std::vector’

int main() { std::vector<int> v;}

Wednesday, November 7, 12

Page 70: Gregor modules

Debugging Flow

Wednesday, November 7, 12

Page 71: Gregor modules

Debugging Flow

foo.cpp<iostream>

Wednesday, November 7, 12

Page 72: Gregor modules

Debugging Flow

foo.cpp<iostream> Clang ASTs

Wednesday, November 7, 12

Page 73: Gregor modules

Debugging Flow

foo.cpp<iostream> Clang ASTs

foo.o

object code

foo DWARF

iostream DWARF

Wednesday, November 7, 12

Page 74: Gregor modules

Debugging Flow

foo.cpp<iostream> Clang ASTs

foo.o

object code

foo DWARF

iostream DWARF

LLDB

Wednesday, November 7, 12

Page 75: Gregor modules

Debugging Flow

foo.cpp<iostream> Clang ASTs

foo.o

object code

foo DWARF

iostream DWARF

LLDB Clang ASTs

Wednesday, November 7, 12

Page 76: Gregor modules

Debugging Flow

foo.cpp<iostream> Clang ASTs

foo.o

object code

foo DWARF

iostream DWARF

LLDB Clang ASTs

• Round-trip through DWARF is lossy

• Only ‘used’ types, functions available

• Inline functions, template definitions lost

Wednesday, November 7, 12

Page 77: Gregor modules

Redundant Debug Info

foo.cpp<iostream> Clang ASTs

foo.o

object code

foo DWARF

iostream DWARF

LLDB Clang ASTs

Wednesday, November 7, 12

Page 78: Gregor modules

Redundant Debug Info

foo.cpp<iostream> Clang ASTs

foo.o

object code

foo DWARF

iostream DWARF

LLDB Clang ASTs

bar.cpp<iostream> Clang ASTs

bar.o

object code

foo DWARF

iostream DWARF

Wednesday, November 7, 12

Page 79: Gregor modules

Redundant Debug Info

foo.cpp<iostream> Clang ASTs

foo.o

object code

foo DWARF

iostream DWARF

LLDB Clang ASTs

bar.cpp<iostream> Clang ASTs

bar.o

object code

foo DWARF

iostream DWARF

Wednesday, November 7, 12

Page 80: Gregor modules

Debugging with Modules

foo.cpp<iostream> Clang ASTs foo DWARF

foo.o

object code

LLDB Clang ASTs

bar.cpp<iostream> Clang ASTs foo DWARF

bar.o

object code

Wednesday, November 7, 12

Page 81: Gregor modules

Debugging with Modules

foo.cpp<iostream> Clang ASTs foo DWARF

foo.o

object code

LLDB Clang ASTs

bar.cpp<iostream> Clang ASTs foo DWARF

bar.o

object code

std.iostream module

Wednesday, November 7, 12

Page 82: Gregor modules

Debugging with Modules

• Improved build performance

• Compiler emits less DWARF

• Linker de-duplicates less DWARF

Wednesday, November 7, 12

Page 83: Gregor modules

Debugging with Modules

• Improved build performance

• Compiler emits less DWARF

• Linker de-duplicates less DWARF

• Improved debugging experience

• Perfect AST fidelity in debugger

• Debugger doesn’t need to search DWARF

Wednesday, November 7, 12

Page 84: Gregor modules

Modules Summary

Wednesday, November 7, 12

Page 85: Gregor modules

Modules Summary

• Modules are a huge potential win for C(++)

• Compile/build time improvements

• Fix various preprocessor problems

• Far better tool experience

Wednesday, November 7, 12

Page 86: Gregor modules

Modules Summary

• Modules are a huge potential win for C(++)

• Compile/build time improvements

• Fix various preprocessor problems

• Far better tool experience

• Design enables smooth transition path

Wednesday, November 7, 12

Page 87: Gregor modules

Modules Summary

• Modules are a huge potential win for C(++)

• Compile/build time improvements

• Fix various preprocessor problems

• Far better tool experience

• Design enables smooth transition path

• Clang implementation underway

Wednesday, November 7, 12