[Tex/LaTex] How to reference line numbers in an external source file (e.g. C++) in a maintainable way

cross-referencingexternal filessourcecode

I doubt there's a very efficient way to do this, but LaTeX seems to be capable of just about anything. I'm writing up a document to explain a piece of C++ source code to future users of the package. The source code is part of a 2,000,000+ line package with dozens of developers. The particular section of code I'm working on spans only a couple thousand lines, but it is complicated enough that typical means of documentation were getting too tedious (e.g. source code comments, doxygen, etc.). I would like to be able to refer to lines of code in my explanatory TeX document, but as the code is still partially under development, those line numbers can (more accurately, will) change. My current approach is to just say that all line numbers just refer to lines at a particular repository revision, but that isn't very satisfactory. I'm not opposed to putting some sort of identifying marks as comments in my code that LaTeX would parse out to generate line numbers, especially if such labels are (at least somewhat) human readable. Any ideas?

Here's a minimal-ish example of the kind of thing I'm looking for. Take it with a grain of salt, because the main problem I'm trying to address is that my particular use case is so far from minimal.

hello.cc:

#include <iostream>

int main() {
    std::cout << "Hello World" << std::endl;  // %label{sc:greet}
    return 0;
}

algorithm.tex:

\documentclass[12pt]{article} % or whatever
\usepackage{something-magical} % i.e. I need this, would define something like \coderef
\begin{document}
In this program, line \coderef{hello.cc}{sc:greet} greets the user.
\end{document}

which would ideally output something like:

Possible output

Best Answer

Under the assumption that you want, not only to reference, but also to typeset your C++ source code somewhere in your document, you can use the listings package, define a character to escape to LaTeX (left quote in my example), and write a \label{...} in your source code within a pair of such escape characters. Just make sure you choose your escape character wisely; if it occurs in places where you don't intend to escape to LaTeX, you'll run into trouble when you try to typeset your code.

If you plan to always place your LaTeX labels within an end-of-line C++ comment, and you don't want those comments to be printed in your PDF, you can define a listings "to-the-end-of-the-line" delimiter to uniquely identify such comments, using, for instance,

moredelim=[il][]{//latexlabel}

The listings package will then detect any occurence of //latexlabel and will not print it; note that listings will print any unescaped text that follows //latexlabel, though.

Feel free to customise/shorten that delimiter; //latexlabel may be a bit too long for your taste.

enter image description here

\documentclass{article}

\usepackage{filecontents} % only to write your code to hello.cpp
\begin{filecontents*}{hello.cpp}
#include <iostream>

int main() {
    std::cout << "Hello World" << std::endl; //latexlabel `\label{sc:greet}`
    return 0; // another comment that does get typeset
}
\end{filecontents*}

\usepackage{listings}
\lstset
{
    language=C++,
    escapechar=`,
    numbers=left,
    moredelim=[il][]{//latexlabel},
}

\begin{document}

\section{Comments on the implementation}
In this program, line~\ref{sc:greet} greets the user.

\section{Source code}
\lstinputlisting{hello.cpp}
\end{document}
Related Question