-
Notifications
You must be signed in to change notification settings - Fork 27
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
Hook for debugging shared libraries in Visual Studio #121
Changes from 9 commits
6cf9cc1
c355dfd
1cc8980
7374782
c1231cf
cc25825
da05d4c
a63049a
ca13d8d
907169b
d15cc2e
05c5a12
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
from conan.tools.files import copy | ||
import glob | ||
import json | ||
import os | ||
import re | ||
from io import StringIO | ||
from conans.errors import ConanException | ||
|
||
|
||
def post_package(conanfile): | ||
if conanfile.settings.get_safe("os") != "Windows" or conanfile.settings.get_safe("compiler") != "msvc": | ||
return | ||
conanfile.output.info("PDBs post package hook running") | ||
search_package_dll = os.path.join(conanfile.package_folder, "**/*.dll") | ||
package_dll = glob.glob(search_package_dll, recursive=True) | ||
if len(package_dll) == 0: | ||
return | ||
# Find dumpbin path | ||
output = StringIO() | ||
try: | ||
conanfile.run( | ||
r'"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -find "**\dumpbin.exe" -format json', | ||
stdout=output, scope="") | ||
except ConanException: | ||
raise ConanException( | ||
"Failed to locate dumpbin.exe which is needed to locate the PDBs and copy them to package folder.") | ||
dumpbin_path = json.loads(str(output.getvalue()))[0] | ||
|
||
for dll_path in package_dll: | ||
# Use dumpbin to get the pdb path from each dll | ||
dumpbin_output = StringIO() | ||
conanfile.run(rf'"{dumpbin_path}" /PDBPATH {dll_path}', stdout=dumpbin_output) | ||
dumpbin = str(dumpbin_output.getvalue()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Usually, what paths are returned here? I just realized that for example most CCI recipes remove the pdbs in the package method, and if tyhis happens after the package, maybe the pdbs do not exist anymore for the interested recipes - I'm saying that maybe we shoukd have a way to avoid those pdb deletions in the first place? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you give me an example of a recipe that does this so I can check how it works? As I understand it dumpbin gets the path of were the PDB is originally located, this is usually (always?) where the library is created which should be the build folder not the package one. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tested this and everything is working fine as expected! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be fine. Having a look at https://learn.microsoft.com/en-us/cpp/build/reference/pdbpath?view=msvc-170, it should return the path embedded in the binary, that should be the path in the build folder where the binary was originated. As this is a post_package hook, it should work even if the package() method deletes the pdbs because the hook is executed after the method 😄 |
||
pdb_path = re.search(r"'.*\.pdb'", dumpbin) | ||
if pdb_path: | ||
pdb_path = pdb_path.group()[1:-1] | ||
# Copy the corresponding pdb file from the build to the package folder | ||
conanfile.output.info( | ||
f"copying {os.path.basename(pdb_path)} from {os.path.dirname(pdb_path)} to {os.path.dirname(dll_path)}") | ||
copy(conanfile, os.path.basename(pdb_path), os.path.dirname(pdb_path), os.path.dirname(dll_path)) | ||
juansblanco marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,46 @@ | ||
import os | ||
import tempfile | ||
import json | ||
import platform | ||
|
||
import pytest | ||
|
||
from tools import run | ||
|
||
|
||
@pytest.fixture(autouse=True) | ||
def conan_test(): | ||
old_env = dict(os.environ) | ||
env_vars = {'CONAN_HOME': tempfile.mkdtemp(suffix='conans')} | ||
os.environ.update(env_vars) | ||
current = tempfile.mkdtemp(suffix='conans') | ||
cwd = os.getcwd() | ||
os.chdir(current) | ||
try: | ||
yield | ||
finally: | ||
os.chdir(cwd) | ||
os.environ.clear() | ||
os.environ.update(old_env) | ||
|
||
|
||
@pytest.mark.win32 | ||
def test_copy_pdb_hook(): | ||
print("This is a placeholder for future tests") | ||
repo = os.path.join(os.path.dirname(__file__), "..") | ||
run(f'conan config install {repo}') | ||
conan_home = run('conan config home').strip() | ||
hooks_path = os.path.join(conan_home, 'extensions', 'hooks') | ||
old_file = os.path.join(hooks_path, '_hook_copy_pdbs_to_package.py') | ||
new_file = os.path.join(hooks_path, 'hook_copy_pdbs_to_package.py') | ||
os.rename(old_file, new_file) | ||
run('conan profile detect') | ||
run('conan new cmake_lib -d name=lib -d version=1.0') | ||
out = run('conan create . -s build_type=Debug -o "*:shared=True" -tf=""') | ||
assert "PDBs post package hook running" in out | ||
list_output = run('conan list lib/1.0:* --format=json') | ||
list_json = json.loads(list_output) | ||
revision = list_json['Local Cache']['lib/1.0']['revisions'].values() | ||
revision_info = next(iter(revision)) | ||
package_id = next(iter(revision_info['packages'])) | ||
path = run(fr'conan cache path lib/1.0:{package_id}').strip() | ||
assert os.path.isfile(os.path.join(path, 'bin', 'lib.pdb')) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
from conan.errors import ConanException will be more future-proof