Skip to content

Repobuild Cpp Tutorial

Christopher Van Arsdale edited this page Oct 8, 2013 · 10 revisions

Overview

This will help you create a new "repobuild" based project. This tutorial is in C++.

Step 1: Install Repobuild

If you have not already, install repobuild (see README)

Step 2: Creating a new github project
  1. Fork the example_cpp project: https://github.com/chrisvana/repobuild_cpp_example
  2. Set up the repository locally:
$ git clone https://github.com/<username>/repobuild_cpp_example
$ cd repobuild_cpp_example
Step 3: Create the Printer Library

Currently, the BUILD file looks like this:

[
// This is empty!
]

We are going to create a new library called "printer"

[
 { "cc_library": {
    "name": "printer",
    "cc_headers": [ "printer.h" ],
    "cc_sources": [ "printer.cc" ]
 } }
]

And now create printer.h:

// This is an example printer!
#ifndef _PRINTER_H__
#define _PRINTER_H__

namespace printer {
class Printer {
 public:
  Printer() {}
  ~Printer() {}
  void PrintMyLines();
};
}  // namespace printer

#endif  // _PRINTER_H__

And printer.cc:

// My printer implementation!
#include <iostream>
#include "printer.h"

namespace printer {

void Printer::PrintMyLines() {
  std::cout << "My lines are pretty uninteresting." << std::endl;
}

}  // namespace printer
Step 4: Compile the Printer Library

Run repobuild:

$ repobuild ":printer"
Processing: //:printer
Generating: Makefile
$ # Note: if your ld binary is old, you may need to run:
$ # repobuild ":printer" --enable_flto_object_files=false
$

Now run make:

$ make
Compiling:  printer.cc (c++)
$ # This should have built a .o file:
$ ls .gen-obj/*.o
.gen-obj/printer.o
$

Great, you have now built a static library for printer!

Step 5: Commit your changes

Optionally, commit your changes:

$ # The makefile was auto-generated by repobuild:
$ git add Makefile
$ git add BUILD
$ git add printer.h printer.cc
$ git commit -m 'up to step 5'
$ git push
$

Your client should now look like this.

Step 6: Build a Binary

We are going to add a binary, so edit the BUILD file:

[
 { "cc_library": {
    "name": "printer",
    "cc_headers": [ "printer.h" ],
    "cc_sources": [ "printer.cc" ]
 } },
 { "cc_binary": {
    "name": "printer_main",
    "cc_sources": [ "printer_main.cc" ],
    "dependencies": [ ":printer" ]
 } }
]

And now add printer_main.cc:

// Binary to run our printer!

#include "printer.h"

int main(int argc, char** argv) {
  printer::Printer print;
  print.PrintMyLines();
  return 0;
}

And run repobuild/make again:

$ repobuild ":printer_main"
Processing: //:printer_main
Processing: //:printer
Processing: //:printer_main.0
Processing: //:printer_main
Generating: Makefile
$ make
Compiling:  printer_main.cc (c++)
Linking:    .gen-obj/printer_main
$ # This should have generated a binary:
$ ls bin/printer_main
bin/printer_main

Now you can run your binary

$ bin/printer_main 
My lines are pretty uninteresting.
Step 7: Commit Your Binary

Optionally, commit your changes:

$ # The makefile was auto-generated by repobuild:
$ git add Makefile
$ git add BUILD
$ git add printer_main.cc
$ git commit -m 'up to step 7'
$ git push
$

Your client should now look like this.

Step 8: Adding Remote Library

Add the "common" submodule

$ git submodule add https://github.com/chrisvana/common.git
$ ls common
BUILD       LICENSE     README.md   __init__.py base        file        log         strings     test        third_party util
$

Note: If you were clone this project after adding "common", repobuild would automatically initialize "common" when required without manually running "git submodule ...". This allows submodules to collectively contain a lot of code without having to pull it all down locally.

Now, let's add binary flags to printer.cc. First, update printer's dependencies in the BUILD file:

[
 { "cc_library": {
    "name": "printer",
    "cc_headers": [ "printer.h" ],
    "cc_sources": [ "printer.cc" ],
    "dependencies": [ "//common/base:flags" ]
 } },
 { "cc_binary": {
    "name": "printer_main",
    "cc_sources": [ "printer_main.cc" ],
    "dependencies": [ ":printer" ]
 } }
]

Second, update printer with a flag:

// My printer implementation!
#include <iostream>
#include "printer.h"
#include "common/base/flags.h"

// These flag values can be specified at run time like:
// bin/printer_main --my_lines="something else!"
DEFINE_string(my_lines, "My lines are user controlled.",
              "User specified lines.");

namespace printer {

void Printer::PrintMyLines() {
  std::cout << FLAGS_my_lines << std::endl;
}

}  // namespace printer

Next, let's update our binary to make sure it parses the flag. Step 1, update the BUILD file again:

[
 { "cc_library": {
    "name": "printer",
    "cc_headers": [ "printer.h" ],
    "cc_sources": [ "printer.cc" ],
    "dependencies": [ "//common/base:flags" ]
 } },
 { "cc_binary": {
    "name": "printer_main",
    "cc_sources": [ "printer_main.cc" ],
    "dependencies": [ ":printer", "//common/base:init" ]
 } }
]

And printer_main.cc to do the parsing:

// Binary to run our printer!

#include "common/base/init.h"
#include "printer.h"

int main(int argc, char** argv) {
  InitProgram(&argc, &argv);  // command line flag parsing, etc.
  printer::Printer print;
  print.PrintMyLines();
  return 0;
}

Ok, let's build it!

$ repobuild ":printer_main"
Processing: //:printer_main
Processing: //:printer
Processing: //common/base:init
Processing: //:printer_main.0
Processing: //common/base:flags
Processing: //common/log:log
Processing: //common/third_party/google/init:init
Processing: //common:auto_.0
Processing: //:printer_main
Processing: //common/third_party/google/gflags:gflags
Processing: //common/third_party/google/glog:glog
Processing: //common/third_party/google/glog:glog_gen
Processing: //common/third_party/google/glog:glog_gen.0
Processing: //common/third_party/google/glog:glog_gen.1
Processing: //common/third_party/google/glog:glog_gen.1.0
Generating: Makefile
$ make -j8
Compiling:  common/third_party/google/gflags/src/gflags.cc (c++)
Compiling:  common/third_party/google/gflags/src/gflags_completions.cc (c++)
Compiling:  common/third_party/google/gflags/src/gflags_nc.cc (c++)
Compiling:  common/third_party/google/gflags/src/gflags_reporting.cc (c++)
Compiling:  printer.cc (c++)
Autoconf:   //common/third_party/google/glog:glog_gen.0
Make:       //common/third_party/google/glog:glog_gen.1.0
Compiling:  common/base/init.cc (c++)
Compiling:  printer_main.cc (c++)
Linking:    .gen-obj/printer_main

You can now run a command like:

$ bin/printer_main --my_lines="That's not a knife"
That's not a knife

Your client should now look like this.

Step 9: Commit Your Submodule

Optionally, commit your changes:

$ git add BUILD Makefile printer.cc printer_main.cc common
$ git commit -m 'up to step 9'
$ git push

Conclusion

Congratulations, you've built a binary that depends on a bunch of other libraries. Check out some other examples: https://github.com/chrisvana/repobuild/wiki/Examples