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

Add CMake generation function #1

Open
Qix- opened this issue Feb 12, 2019 · 8 comments
Open

Add CMake generation function #1

Qix- opened this issue Feb 12, 2019 · 8 comments

Comments

@Qix-
Copy link
Contributor

Qix- commented Feb 12, 2019

Not sure exactly how it should be provided (directly in the CMakeLists.txt here? as a package for find_package()?) but here is the toolchain function I've been using to create Terra projects with terrac:

function (terra_module_directories)
	foreach (arg IN LISTS ARGN)
		list (APPEND TERRA_MODPATH "${arg}")
	endforeach ()
	set (TERRA_MODPATH "${TERRA_MODPATH}" PARENT_SCOPE)
endfunction ()

function (add_terra_executable ARG_NAME)
	if (ARGC LESS 2)
		message (FATAL_ERROR "add_terra_executable(name, ...) requires at least one source")
	endif ()

	get_property(dirs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES)
	foreach (DIR IN LISTS dirs)
		list (APPEND includedirs "-I")
		list (APPEND includedirs "${DIR}")
	endforeach ()
	foreach (modpath IN LISTS TERRA_MODPATH)
		list (APPEND includedirs "-m")
		list (APPEND includedirs "${modpath}")
	endforeach ()

	foreach (file IN LISTS ARGN)
		get_filename_component (ext "${file}" EXT)
		if (ext STREQUAL ".t")
			get_filename_component (fileabs "${file}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
			file (TO_CMAKE_PATH "${fileabs}" fileabssrc)
			file (RELATIVE_PATH filerel "${CMAKE_CURRENT_SOURCE_DIR}" "${fileabssrc}")
			get_filename_component (output "${filerel}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}")
			get_filename_component (filedir "${fileabs}" DIRECTORY)

			message(STATUS "terra: ${output}.o")
			add_custom_command (
				OUTPUT "${output}.o"
				COMMAND "$<TARGET_FILE:terrac>" ARGS -I "${filedir}" -P "${CMAKE_CURRENT_BINARY_DIR}" -D "${output}.d" -o "${output}.o" ${includedirs} "${fileabs}"
				WORKING_DIRECTORY "${filedir}"
				MAIN_DEPENDENCY "${fileabs}"
				DEPFILE "${output}.d"
				COMMENT "Terra: ${output}.o"
				VERBATIM
				COMMAND_EXPAND_LISTS)

			list (APPEND link_sources "${output}.o")
		else ()
			list (APPEND compile_sources "${file}")
		endif ()
	endforeach ()

	list (LENGTH compile_sources compile_sources_count)
	if (compile_sources_count EQUAL 0)
		message (FATAL_ERROR "add_terra_executable(name, ...) requires at least one non-terra source file (I know, I know...)")
	endif ()

	list (LENGTH link_sources link_sources_count)

	add_executable ("${ARG_NAME}" ${compile_sources})
	if (link_sources_count GREATER 0)
		target_link_libraries ("${ARG_NAME}" ${link_sources})

		add_custom_target ("${ARG_NAME}__terra"
			DEPENDS "${link_sources}")

		add_dependencies ("${ARG_NAME}" "${ARG_NAME}__terra")
		add_dependencies ("${ARG_NAME}__terra" terrac)
	endif ()
endfunction ()

Anyone have any preferences on how this gets distributed?

@Qix-
Copy link
Contributor Author

Qix- commented Feb 12, 2019

Note that this requires that terrac be built by your current CMake configuration, though it should be fairly trivial to use find_program() if the terrac target doesn't exist.

@elliottslaughter
Copy link
Member

Doesn't CMake have a notion of exports? Like when you build LLVM, you get a bunch of files like share/llvm/cmake/LLVMConfig.cmake, which allow you do things like find(LLVM) in your CMake code without writing your own FindLLVM.cmake. Maybe we could do something similar here so that users can just write:

find(TerraCompiler)

Or something similar and get those definitions? Then it's something that just comes along with every installation instead of being something users are expecting to copy-and-paste into their projects.

@elliottslaughter
Copy link
Member

And we could do something similar in the main project so that you can get:

find(TerraExecutable)

To get the path to the main Terra executable. (So TerraExecutable for terra, TerraCompiler for terrac.)

@Qix-
Copy link
Contributor Author

Qix- commented Feb 12, 2019

I've not seen generated find scripts, but even then, it wouldn't generate the logic to create the add_terra_executable.

@elliottslaughter
Copy link
Member

I'm not sure why you don't think it wouldn't work?

Using LLVM as an example, here's what I get in an installation of LLVM 3.8.0 (this is the contents of share/llvm/cmake): https://gist.github.com/elliottslaughter/64d5d5d9d9e5cbfc853bac1d32cdc131

Per the documentation for find_package, when you do find(LLVM), CMake will search for LLVMConfig.cmake or LLVM-config.cmake using CMAKE_PREFIX_PATH to guide the search. So in this case we'll be loading LLVMConfig.cmake: https://gist.github.com/elliottslaughter/64d5d5d9d9e5cbfc853bac1d32cdc131#file-llvmconfig-cmake

As best I can tell this is just arbitrary CMake code. There may be conventions but you can really do anything you want. For example, LLVMConfig.cmake includes LLVM-Config.cmake, which has various functions and macros: https://gist.github.com/elliottslaughter/64d5d5d9d9e5cbfc853bac1d32cdc131#file-llvm-config-cmake

There are also files that seem to sit on the side to provide extra utilities as well, that the user could manually include if they wanted: https://gist.github.com/elliottslaughter/64d5d5d9d9e5cbfc853bac1d32cdc131#file-handlellvmoptions-cmake

Anyway, I think LLVM goes a bit far here, and the amount of functionality is a bit overwhelming (and undocumented as best I can tell), but a more modest amount of functionality could be quite welcome, in my opinion, in terms of making things work "out of the box" for users.

@Qix-
Copy link
Contributor Author

Qix- commented Feb 15, 2019

Sorry @elliottslaughter I misunderstood what you were saying. This is exactly how it should work - people should be able to do find_package(TerraCompiler REQUIRED) and get add_terra_executable() and terra_module_directories().

The above code doesn't define TerraCompiler_FOUND or whatever, but that is pretty trivial to add to make it find_package()-friendly.

This assumes that terrac is being installed to the system, though, which means we'd have to package + distribute this.

@elliottslaughter
Copy link
Member

Doesn't it still work if you install to a local directory, as long as you set CMAKE_PREFIX_PATH? I mean, if it's a local build, you'll have to configure the location of terrac anyway, so it might as well be through a standard mechanism, right?

@Qix-
Copy link
Contributor Author

Qix- commented Feb 19, 2019

Doesn't it still work if you install to a local directory, as long as you set CMAKE_PREFIX_PATH?

Yes but I've been using it as a subdirectory for cmake via add_subdirectory, therefore I don't need to search for it - I just use a generator variable substitution to get the full path of the built executable.

If it were built and installed, then you'd have to use find_program to get the path of the executable.

The check for which strategy to use can be done using if(TARGET terrac) if memory serves.

Then, the script above would be included by the Terrac cmakelists (making it usable by projects that embed it into their projects) as well as installed to the system's default cmake path (making it usable by projects that just have Terra installed globally).

Hopefully that makes sense :)

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

2 participants