Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Object files from compile goal should be linked in test-compile #180

Open
Tubeliar opened this issue Jun 16, 2015 · 3 comments
Open

Object files from compile goal should be linked in test-compile #180

Tubeliar opened this issue Jun 16, 2015 · 3 comments
Milestone

Comments

@Tubeliar
Copy link
Contributor

I have a C++ project with several source files in src/main/c++ with their headers in src/main/include, and one source file in src/test/c++. The single test file is of course supposed to validate output from several functions in the main source.

When issuing the normal compile goal all is well because all the necessary files are at hand. When the test-compile goal is run the compilation itself succeeds, so all the header files from the main source are found. However I then get linker errors caused by undefined references to the symbols in the main source.

So while the header files are available to compile, the object files to link aren't.

@ctrueden ctrueden added this to the unscheduled milestone Aug 6, 2015
@manu4linux
Copy link
Contributor

Hi @ctrueden we are seeing this issue in our builds a lot and I would like investigate further to resolve the issue. Can you please give any hints on how to proceed.

@ctrueden
Copy link
Contributor

@manu4linux I don't have a lot of hints, since I am not an expert on this codebase. However, you could start by running with mvn -X to get lots more details on the commands NAR is choosing to run.

@Tubeliar
Copy link
Contributor Author

TL;DR: Just add all object files from the main goal. Test code probably has it's own main, so ignore the object file that has a main function.

I eventually hacked it by adding this code to NarTestCompileMojo.java in method createTest, right at the end just before try/task.execute is called:

        File originalObjectDir = new File(new File(getTargetDirectory(), "obj"), getAOL().toString());
        CommandLineArgument.LocationEnum end = new CommandLineArgument.LocationEnum();
        end.setValue("end");
        for (File f : originalObjectDir.listFiles())
        {
            // File extension should be compared by the comiler's bid system
            if (f.getName().toLowerCase().endsWith(".o"))
            {
                // Use nm to list all the symbols in the object file
                String[] cmd = { "nm", "-C", "--defined-only", f.getAbsolutePath() };
                boolean include = true;
                try
                {
                    Process p = Runtime.getRuntime().exec(cmd);
                    BufferedReader output = new BufferedReader(new InputStreamReader(p.getInputStream()));
                    String line;
                    while((line = output.readLine()) != null)
                    {
                        // If the object file contains main then we must not include it
                        // The test executable must have it's own main
                        if (line.contains("T main"))
                        {
                            include = false;
                            break;
                        }
                    }
                }
                catch (IOException e)
                {
                    getLog().warn("Failed to inspect " + f.getName() + ": " + e);
                    include = false; // Include failed files?
                }
                getLog().info((include ? "Adding  " : "Skipping") + " " + f.getAbsolutePath());
                if (include)
                {
                    // Add the object file to the linker command line
                    LinkerArgument newArg = new LinkerArgument();
                    newArg.setLocation(end);
                    newArg.setValue(f.getAbsolutePath());
                    linkerDefinition.addConfiguredLinkerArg(newArg);
                }
            }
        }

The hackiness is the reason i haven't pushed it. For one it relies on nm being present, which is only valid if you're using C/C++ and using gnu tools. This code lists all the object files from the main compile goal. It searches for the one that contains the main function and ignores that one. I needed this because the test code has a main function as well.

This hack solved my immediate problem but there is more. I think it is actually necessary to recompile the main code. In my case, in the test compile i would like to easure test coverage as well, so i add testOptions -O0 -fprofile-arcs -ftest-coverage. But only the test code is compiled with these options! So i get data about the test code itself, but not about the code it was supposed to test! I solved this by using a different profile where the compile options are added to the main compile goal and so i get measurements for the real code when the test is run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants